blob: 6d11076bbd0228e10cfa4d8ddd2fe1791c3c384a [file] [log] [blame]
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04001#define ASC_VERSION "3.4" /* 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.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04008 * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * All Rights Reserved.
10 *
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
19 * changed its name to ConnectCom Solutions, Inc.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040020 * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 */
22
23/*
24
25 Documentation for the AdvanSys Driver
26
27 A. Linux Kernels Supported by this Driver
28 B. Adapters Supported by this Driver
29 C. Linux source files modified by AdvanSys Driver
30 D. Source Comments
31 E. Driver Compile Time Options and Debugging
32 F. Driver LILO Option
33 G. Tests to run before releasing new driver
34 H. Release History
35 I. Known Problems/Fix List
36 J. Credits (Chronological Order)
37
38 A. Linux Kernels Supported by this Driver
39
40 This driver has been tested in the following Linux kernels: v2.2.18
41 v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86,
42 alpha, and PowerPC platforms.
43
44 B. Adapters Supported by this Driver
45
46 AdvanSys (Advanced System Products, Inc.) manufactures the following
47 RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
48 (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
49 buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
50 transfer) SCSI Host Adapters for the PCI bus.
51
52 The CDB counts below indicate the number of SCSI CDB (Command
53 Descriptor Block) requests that can be stored in the RISC chip
54 cache and board LRAM. A CDB is a single SCSI command. The driver
55 detect routine will display the number of CDBs available for each
56 adapter detected. The number of CDBs used by the driver can be
57 lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
58
59 Laptop Products:
60 ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater)
61
62 Connectivity Products:
63 ABP510/5150 - Bus-Master ISA (240 CDB)
64 ABP5140 - Bus-Master ISA PnP (16 CDB)
65 ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
66 ABP902/3902 - Bus-Master PCI (16 CDB)
67 ABP3905 - Bus-Master PCI (16 CDB)
68 ABP915 - Bus-Master PCI (16 CDB)
69 ABP920 - Bus-Master PCI (16 CDB)
70 ABP3922 - Bus-Master PCI (16 CDB)
71 ABP3925 - Bus-Master PCI (16 CDB)
72 ABP930 - Bus-Master PCI (16 CDB)
73 ABP930U - Bus-Master PCI Ultra (16 CDB)
74 ABP930UA - Bus-Master PCI Ultra (16 CDB)
75 ABP960 - Bus-Master PCI MAC/PC (16 CDB)
76 ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
77
78 Single Channel Products:
79 ABP542 - Bus-Master ISA with floppy (240 CDB)
80 ABP742 - Bus-Master EISA (240 CDB)
81 ABP842 - Bus-Master VL (240 CDB)
82 ABP940 - Bus-Master PCI (240 CDB)
83 ABP940U - Bus-Master PCI Ultra (240 CDB)
84 ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
85 ABP970 - Bus-Master PCI MAC/PC (240 CDB)
86 ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
87 ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
88 ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
89 ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
90 ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
91
92 Multi-Channel Products:
93 ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
94 ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
95 ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
96 ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
97 ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
98 ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
99 ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
100 ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
101 ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB)
102
103 C. Linux source files modified by AdvanSys Driver
104
105 This section for historical purposes documents the changes
106 originally made to the Linux kernel source to add the advansys
107 driver. As Linux has changed some of these files have also
108 been modified.
109
110 1. linux/arch/i386/config.in:
111
112 bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y
113
114 2. linux/drivers/scsi/hosts.c:
115
116 #ifdef CONFIG_SCSI_ADVANSYS
117 #include "advansys.h"
118 #endif
119
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100120 and after "static struct scsi_host_template builtin_scsi_hosts[] =":
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122 #ifdef CONFIG_SCSI_ADVANSYS
123 ADVANSYS,
124 #endif
125
126 3. linux/drivers/scsi/Makefile:
127
128 ifdef CONFIG_SCSI_ADVANSYS
129 SCSI_SRCS := $(SCSI_SRCS) advansys.c
130 SCSI_OBJS := $(SCSI_OBJS) advansys.o
131 else
132 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o
133 endif
134
135 4. linux/init/main.c:
136
137 extern void advansys_setup(char *str, int *ints);
138
139 and add the following lines to the bootsetups[] array.
140
141 #ifdef CONFIG_SCSI_ADVANSYS
142 { "advansys=", advansys_setup },
143 #endif
144
145 D. Source Comments
146
147 1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
148
149 2. This driver should be maintained in multiple files. But to make
150 it easier to include with Linux and to follow Linux conventions,
151 the whole driver is maintained in the source files advansys.h and
152 advansys.c. In this file logical sections of the driver begin with
153 a comment that contains '---'. The following are the logical sections
154 of the driver below.
155
156 --- Linux Version
157 --- Linux Include File
158 --- Driver Options
159 --- Debugging Header
160 --- Asc Library Constants and Macros
161 --- Adv Library Constants and Macros
162 --- Driver Constants and Macros
163 --- Driver Structures
164 --- Driver Data
165 --- Driver Function Prototypes
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100166 --- Linux 'struct scsi_host_template' and advansys_setup() Functions
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 --- Loadable Driver Support
168 --- Miscellaneous Driver Functions
169 --- Functions Required by the Asc Library
170 --- Functions Required by the Adv Library
171 --- Tracing and Debugging Functions
172 --- Asc Library Functions
173 --- Adv Library Functions
174
175 3. The string 'XXX' is used to flag code that needs to be re-written
176 or that contains a problem that needs to be addressed.
177
178 4. I have stripped comments from and reformatted the source for the
179 Asc Library and Adv Library to reduce the size of this file. This
180 source can be found under the following headings. The Asc Library
181 is used to support Narrow Boards. The Adv Library is used to
182 support Wide Boards.
183
184 --- Asc Library Constants and Macros
185 --- Adv Library Constants and Macros
186 --- Asc Library Functions
187 --- Adv Library Functions
188
189 E. Driver Compile Time Options and Debugging
190
191 In this source file the following constants can be defined. They are
192 defined in the source below. Both of these options are enabled by
193 default.
194
195 1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
196
197 Enabling this option adds assertion logic statements to the
198 driver. If an assertion fails a message will be displayed to
199 the console, but the system will continue to operate. Any
200 assertions encountered should be reported to the person
201 responsible for the driver. Assertion statements may proactively
202 detect problems with the driver and facilitate fixing these
203 problems. Enabling assertions will add a small overhead to the
204 execution of the driver.
205
206 2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled)
207
208 Enabling this option adds tracing functions to the driver and
209 the ability to set a driver tracing level at boot time. This
210 option will also export symbols not required outside the driver to
211 the kernel name space. This option is very useful for debugging
212 the driver, but it will add to the size of the driver execution
213 image and add overhead to the execution of the driver.
214
215 The amount of debugging output can be controlled with the global
216 variable 'asc_dbglvl'. The higher the number the more output. By
217 default the debug level is 0.
218
219 If the driver is loaded at boot time and the LILO Driver Option
220 is included in the system, the debug level can be changed by
221 specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
222 first three hex digits of the pseudo I/O Port must be set to
223 'deb' and the fourth hex digit specifies the debug level: 0 - F.
224 The following command line will look for an adapter at 0x330
225 and set the debug level to 2.
226
227 linux advansys=0x330,0,0,0,0xdeb2
228
229 If the driver is built as a loadable module this variable can be
230 defined when the driver is loaded. The following insmod command
231 will set the debug level to one.
232
233 insmod advansys.o asc_dbglvl=1
234
235 Debugging Message Levels:
236 0: Errors Only
237 1: High-Level Tracing
238 2-N: Verbose Tracing
239
240 To enable debug output to console, please make sure that:
241
242 a. System and kernel logging is enabled (syslogd, klogd running).
243 b. Kernel messages are routed to console output. Check
244 /etc/syslog.conf for an entry similar to this:
245
246 kern.* /dev/console
247
248 c. klogd is started with the appropriate -c parameter
249 (e.g. klogd -c 8)
250
251 This will cause printk() messages to be be displayed on the
252 current console. Refer to the klogd(8) and syslogd(8) man pages
253 for details.
254
255 Alternatively you can enable printk() to console with this
256 program. However, this is not the 'official' way to do this.
257 Debug output is logged in /var/log/messages.
258
259 main()
260 {
261 syscall(103, 7, 0, 0);
262 }
263
264 Increasing LOG_BUF_LEN in kernel/printk.c to something like
265 40960 allows more debug messages to be buffered in the kernel
266 and written to the console or log file.
267
268 3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0)
269
270 Enabling this option adds statistics collection and display
271 through /proc to the driver. The information is useful for
272 monitoring driver and device performance. It will add to the
273 size of the driver execution image and add minor overhead to
274 the execution of the driver.
275
276 Statistics are maintained on a per adapter basis. Driver entry
277 point call counts and transfer size counts are maintained.
278 Statistics are only available for kernels greater than or equal
279 to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
280
281 AdvanSys SCSI adapter files have the following path name format:
282
283 /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
284
285 This information can be displayed with cat. For example:
286
287 cat /proc/scsi/advansys/0
288
289 When ADVANSYS_STATS is not defined the AdvanSys /proc files only
290 contain adapter and device configuration information.
291
292 F. Driver LILO Option
293
294 If init/main.c is modified as described in the 'Directions for Adding
295 the AdvanSys Driver to Linux' section (B.4.) above, the driver will
296 recognize the 'advansys' LILO command line and /etc/lilo.conf option.
297 This option can be used to either disable I/O port scanning or to limit
298 scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and
299 PCI boards will still be searched for and detected. This option only
300 affects searching for ISA and VL boards.
301
302 Examples:
303 1. Eliminate I/O port scanning:
304 boot: linux advansys=
305 or
306 boot: linux advansys=0x0
307 2. Limit I/O port scanning to one I/O port:
308 boot: linux advansys=0x110
309 3. Limit I/O port scanning to four I/O ports:
310 boot: linux advansys=0x110,0x210,0x230,0x330
311
312 For a loadable module the same effect can be achieved by setting
313 the 'asc_iopflag' variable and 'asc_ioport' array when loading
314 the driver, e.g.
315
316 insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
317
318 If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
319 I/O Port may be added to specify the driver debug level. Refer to
320 the 'Driver Compile Time Options and Debugging' section above for
321 more information.
322
323 G. Tests to run before releasing new driver
324
325 1. In the supported kernels verify there are no warning or compile
326 errors when the kernel is built as both a driver and as a module
327 and with the following options:
328
329 ADVANSYS_DEBUG - enabled and disabled
330 CONFIG_SMP - enabled and disabled
331 CONFIG_PROC_FS - enabled and disabled
332
333 2. Run tests on an x86, alpha, and PowerPC with at least one narrow
334 card and one wide card attached to a hard disk and CD-ROM drive:
335 fdisk, mkfs, fsck, bonnie, copy/compare test from the
336 CD-ROM to the hard drive.
337
338 H. Release History
339
340 BETA-1.0 (12/23/95):
341 First Release
342
343 BETA-1.1 (12/28/95):
344 1. Prevent advansys_detect() from being called twice.
345 2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'.
346
347 1.2 (1/12/96):
348 1. Prevent re-entrancy in the interrupt handler which
349 resulted in the driver hanging Linux.
350 2. Fix problem that prevented ABP-940 cards from being
351 recognized on some PCI motherboards.
352 3. Add support for the ABP-5140 PnP ISA card.
353 4. Fix check condition return status.
354 5. Add conditionally compiled code for Linux v1.3.X.
355
356 1.3 (2/23/96):
357 1. Fix problem in advansys_biosparam() that resulted in the
358 wrong drive geometry being returned for drives > 1GB with
359 extended translation enabled.
360 2. Add additional tracing during device initialization.
361 3. Change code that only applies to ISA PnP adapter.
362 4. Eliminate 'make dep' warning.
363 5. Try to fix problem with handling resets by increasing their
364 timeout value.
365
366 1.4 (5/8/96):
367 1. Change definitions to eliminate conflicts with other subsystems.
368 2. Add versioning code for the shared interrupt changes.
369 3. Eliminate problem in asc_rmqueue() with iterating after removing
370 a request.
371 4. Remove reset request loop problem from the "Known Problems or
372 Issues" section. This problem was isolated and fixed in the
373 mid-level SCSI driver.
374
375 1.5 (8/8/96):
376 1. Add support for ABP-940U (PCI Ultra) adapter.
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700377 2. Add support for IRQ sharing by setting the IRQF_SHARED flag for
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 request_irq and supplying a dev_id pointer to both request_irq()
379 and free_irq().
380 3. In AscSearchIOPortAddr11() restore a call to check_region() which
381 should be used before I/O port probing.
382 4. Fix bug in asc_prt_hex() which resulted in the displaying
383 the wrong data.
384 5. Incorporate miscellaneous Asc Library bug fixes and new microcode.
385 6. Change driver versioning to be specific to each Linux sub-level.
386 7. Change statistics gathering to be per adapter instead of global
387 to the driver.
388 8. Add more information and statistics to the adapter /proc file:
389 /proc/scsi/advansys[0...].
390 9. Remove 'cmd_per_lun' from the "Known Problems or Issues" list.
391 This problem has been addressed with the SCSI mid-level changes
392 made in v1.3.89. The advansys_select_queue_depths() function
393 was added for the v1.3.89 changes.
394
395 1.6 (9/10/96):
396 1. Incorporate miscellaneous Asc Library bug fixes and new microcode.
397
398 1.7 (9/25/96):
399 1. Enable clustering and optimize the setting of the maximum number
400 of scatter gather elements for any particular board. Clustering
401 increases CPU utilization, but results in a relatively larger
402 increase in I/O throughput.
403 2. Improve the performance of the request queuing functions by
404 adding a last pointer to the queue structure.
405 3. Correct problems with reset and abort request handling that
406 could have hung or crashed Linux.
407 4. Add more information to the adapter /proc file:
408 /proc/scsi/advansys[0...].
409 5. Remove the request timeout issue form the driver issues list.
410 6. Miscellaneous documentation additions and changes.
411
412 1.8 (10/4/96):
413 1. Make changes to handle the new v2.1.0 kernel memory mapping
414 in which a kernel virtual address may not be equivalent to its
415 bus or DMA memory address.
416 2. Change abort and reset request handling to make it yet even
417 more robust.
418 3. Try to mitigate request starvation by sending ordered requests
419 to heavily loaded, tag queuing enabled devices.
420 4. Maintain statistics on request response time.
421 5. Add request response time statistics and other information to
422 the adapter /proc file: /proc/scsi/advansys[0...].
423
424 1.9 (10/21/96):
425 1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to
426 make use of mid-level SCSI driver device queue depth flow
427 control mechanism. This will eliminate aborts caused by a
428 device being unable to keep up with requests and eliminate
429 repeat busy or QUEUE FULL status returned by a device.
430 2. Incorporate miscellaneous Asc Library bug fixes.
431 3. To allow the driver to work in kernels with broken module
432 support set 'cmd_per_lun' if the driver is compiled as a
433 module. This change affects kernels v1.3.89 to present.
434 4. Remove PCI BIOS address from the driver banner. The PCI BIOS
435 is relocated by the motherboard BIOS and its new address can
436 not be determined by the driver.
437 5. Add mid-level SCSI queue depth information to the adapter
438 /proc file: /proc/scsi/advansys[0...].
439
440 2.0 (11/14/96):
441 1. Change allocation of global structures used for device
442 initialization to guarantee they are in DMA-able memory.
443 Previously when the driver was loaded as a module these
444 structures might not have been in DMA-able memory, causing
445 device initialization to fail.
446
447 2.1 (12/30/96):
448 1. In advansys_reset(), if the request is a synchronous reset
449 request, even if the request serial number has changed, then
450 complete the request.
451 2. Add Asc Library bug fixes including new microcode.
452 3. Clear inquiry buffer before using it.
453 4. Correct ifdef typo.
454
455 2.2 (1/15/97):
456 1. Add Asc Library bug fixes including new microcode.
457 2. Add synchronous data transfer rate information to the
458 adapter /proc file: /proc/scsi/advansys[0...].
459 3. Change ADVANSYS_DEBUG to be disabled by default. This
460 will reduce the size of the driver image, eliminate execution
461 overhead, and remove unneeded symbols from the kernel symbol
462 space that were previously added by the driver.
463 4. Add new compile-time option ADVANSYS_ASSERT for assertion
464 code that used to be defined within ADVANSYS_DEBUG. This
465 option is enabled by default.
466
467 2.8 (5/26/97):
468 1. Change version number to 2.8 to synchronize the Linux driver
469 version numbering with other AdvanSys drivers.
470 2. Reformat source files without tabs to present the same view
471 of the file to everyone regardless of the editor tab setting
472 being used.
473 3. Add Asc Library bug fixes.
474
475 3.1A (1/8/98):
476 1. Change version number to 3.1 to indicate that support for
477 Ultra-Wide adapters (ABP-940UW) is included in this release.
478 2. Add Asc Library (Narrow Board) bug fixes.
479 3. Report an underrun condition with the host status byte set
480 to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which
481 causes the underrun condition to be ignored. When Linux defines
482 its own DID_UNDERRUN the constant defined in this file can be
483 removed.
484 4. Add patch to AscWaitTixISRDone().
485 5. Add support for up to 16 different AdvanSys host adapter SCSI
486 channels in one system. This allows four cards with four channels
487 to be used in one system.
488
489 3.1B (1/9/98):
490 1. Handle that PCI register base addresses are not always page
491 aligned even though ioremap() requires that the address argument
492 be page aligned.
493
494 3.1C (1/10/98):
495 1. Update latest BIOS version checked for from the /proc file.
496 2. Don't set microcode SDTR variable at initialization. Instead
497 wait until device capabilities have been detected from an Inquiry
498 command.
499
500 3.1D (1/21/98):
501 1. Improve performance when the driver is compiled as module by
502 allowing up to 64 scatter-gather elements instead of 8.
503
504 3.1E (5/1/98):
505 1. Set time delay in AscWaitTixISRDone() to 1000 ms.
506 2. Include SMP locking changes.
507 3. For v2.1.93 and newer kernels use CONFIG_PCI and new PCI BIOS
508 access functions.
509 4. Update board serial number printing.
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700510 5. Try allocating an IRQ both with and without the IRQF_DISABLED
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 flag set to allow IRQ sharing with drivers that do not set
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700512 the IRQF_DISABLED flag. Also display a more descriptive error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 message if request_irq() fails.
514 6. Update to latest Asc and Adv Libraries.
515
516 3.2A (7/22/99):
517 1. Update Adv Library to 4.16 which includes support for
518 the ASC38C0800 (Ultra2/LVD) IC.
519
520 3.2B (8/23/99):
521 1. Correct PCI compile time option for v2.1.93 and greater
522 kernels, advansys_info() string, and debug compile time
523 option.
524 2. Correct DvcSleepMilliSecond() for v2.1.0 and greater
525 kernels. This caused an LVD detection/BIST problem problem
526 among other things.
527 3. Sort PCI cards by PCI Bus, Slot, Function ascending order
528 to be consistent with the BIOS.
529 4. Update to Asc Library S121 and Adv Library 5.2.
530
531 3.2C (8/24/99):
532 1. Correct PCI card detection bug introduced in 3.2B that
533 prevented PCI cards from being detected in kernels older
534 than v2.1.93.
535
536 3.2D (8/26/99):
537 1. Correct /proc device synchronous speed information display.
538 Also when re-negotiation is pending for a target device
539 note this condition with an * and footnote.
540 2. Correct initialization problem with Ultra-Wide cards that
541 have a pre-3.2 BIOS. A microcode variable changed locations
542 in 3.2 and greater BIOSes which caused WDTR to be attempted
543 erroneously with drives that don't support WDTR.
544
545 3.2E (8/30/99):
546 1. Fix compile error caused by v2.3.13 PCI structure change.
547 2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM
548 checksum error for ISA cards.
549 3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level
550 SCSI changes that it depended on were never included in Linux.
551
552 3.2F (9/3/99):
553 1. Handle new initial function code added in v2.3.16 for all
554 driver versions.
555
556 3.2G (9/8/99):
557 1. Fix PCI board detection in v2.3.13 and greater kernels.
558 2. Fix comiple errors in v2.3.X with debugging enabled.
559
560 3.2H (9/13/99):
561 1. Add 64-bit address, long support for Alpha and UltraSPARC.
562 The driver has been verified to work on an Alpha system.
563 2. Add partial byte order handling support for Power PC and
564 other big-endian platforms. This support has not yet been
565 completed or verified.
566 3. For wide boards replace block zeroing of request and
567 scatter-gather structures with individual field initialization
568 to improve performance.
569 4. Correct and clarify ROM BIOS version detection.
570
571 3.2I (10/8/99):
572 1. Update to Adv Library 5.4.
573 2. Add v2.3.19 underrun reporting to asc_isr_callback() and
574 adv_isr_callback(). Remove DID_UNDERRUN constant and other
575 no longer needed code that previously documented the lack
576 of underrun handling.
577
578 3.2J (10/14/99):
579 1. Eliminate compile errors for v2.0 and earlier kernels.
580
581 3.2K (11/15/99):
582 1. Correct debug compile error in asc_prt_adv_scsi_req_q().
583 2. Update Adv Library to 5.5.
584 3. Add ifdef handling for /proc changes added in v2.3.28.
585 4. Increase Wide board scatter-gather list maximum length to
586 255 when the driver is compiled into the kernel.
587
588 3.2L (11/18/99):
589 1. Fix bug in adv_get_sglist() that caused an assertion failure
590 at line 7475. The reqp->sgblkp pointer must be initialized
591 to NULL in adv_get_sglist().
592
593 3.2M (11/29/99):
594 1. Really fix bug in adv_get_sglist().
595 2. Incorporate v2.3.29 changes into driver.
596
597 3.2N (4/1/00):
598 1. Add CONFIG_ISA ifdef code.
599 2. Include advansys_interrupts_enabled name change patch.
600 3. For >= v2.3.28 use new SCSI error handling with new function
601 advansys_eh_bus_reset(). Don't include an abort function
602 because of base library limitations.
603 4. For >= v2.3.28 use per board lock instead of io_request_lock.
604 5. For >= v2.3.28 eliminate advansys_command() and
605 advansys_command_done().
606 6. Add some changes for PowerPC (Big Endian) support, but it isn't
607 working yet.
608 7. Fix "nonexistent resource free" problem that occurred on a module
609 unload for boards with an I/O space >= 255. The 'n_io_port' field
610 is only one byte and can not be used to hold an ioport length more
611 than 255.
612
613 3.3A (4/4/00):
614 1. Update to Adv Library 5.8.
615 2. For wide cards add support for CDBs up to 16 bytes.
616 3. Eliminate warnings when CONFIG_PROC_FS is not defined.
617
618 3.3B (5/1/00):
619 1. Support for PowerPC (Big Endian) wide cards. Narrow cards
620 still need work.
621 2. Change bitfields to shift and mask access for endian
622 portability.
623
624 3.3C (10/13/00):
625 1. Update for latest 2.4 kernel.
626 2. Test ABP-480 CardBus support in 2.4 kernel - works!
627 3. Update to Asc Library S123.
628 4. Update to Adv Library 5.12.
629
630 3.3D (11/22/00):
631 1. Update for latest 2.4 kernel.
632 2. Create patches for 2.2 and 2.4 kernels.
633
634 3.3E (1/9/01):
635 1. Now that 2.4 is released remove ifdef code for kernel versions
636 less than 2.2. The driver is now only supported in kernels 2.2,
637 2.4, and greater.
638 2. Add code to release and acquire the io_request_lock in
639 the driver entrypoint functions: advansys_detect and
640 advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver
641 still holds the io_request_lock on entry to SCSI low-level drivers.
642 This was supposed to be removed before 2.4 was released but never
643 happened. When the mid-level SCSI driver is changed all references
644 to the io_request_lock should be removed from the driver.
645 3. Simplify error handling by removing advansys_abort(),
646 AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are
647 now handled by resetting the SCSI bus and fully re-initializing
648 the chip. This simple method of error recovery has proven to work
649 most reliably after attempts at different methods. Also now only
650 support the "new" error handling method and remove the obsolete
651 error handling interface.
652 4. Fix debug build errors.
653
654 3.3F (1/24/01):
655 1. Merge with ConnectCom version from Andy Kellner which
656 updates Adv Library to 5.14.
657 2. Make PowerPC (Big Endian) work for narrow cards and
658 fix problems writing EEPROM for wide cards.
659 3. Remove interrupts_enabled assertion function.
660
661 3.3G (2/16/01):
662 1. Return an error from narrow boards if passed a 16 byte
663 CDB. The wide board can already handle 16 byte CDBs.
664
665 3.3GJ (4/15/02):
666 1. hacks for lk 2.5 series (D. Gilbert)
667
668 3.3GJD (10/14/02):
669 1. change select_queue_depths to slave_configure
670 2. make cmd_per_lun be sane again
671
672 3.3K [2004/06/24]:
673 1. continuing cleanup for lk 2.6 series
674 2. Fix problem in lk 2.6.7-bk2 that broke PCI wide cards
675 3. Fix problem that oopsed ISA cards
676
677 I. Known Problems/Fix List (XXX)
678
679 1. Need to add memory mapping workaround. Test the memory mapping.
680 If it doesn't work revert to I/O port access. Can a test be done
681 safely?
682 2. Handle an interrupt not working. Keep an interrupt counter in
683 the interrupt handler. In the timeout function if the interrupt
684 has not occurred then print a message and run in polled mode.
685 3. Allow bus type scanning order to be changed.
686 4. Need to add support for target mode commands, cf. CAM XPT.
687
688 J. Credits (Chronological Order)
689
690 Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver
691 and maintained it up to 3.3F. He continues to answer questions
692 and help maintain the driver.
693
694 Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
695 basis for the Linux v1.3.X changes which were included in the
696 1.2 release.
697
698 Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
699 in advansys_biosparam() which was fixed in the 1.3 release.
700
701 Erik Ratcliffe <erik@caldera.com> has done testing of the
702 AdvanSys driver in the Caldera releases.
703
704 Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
705 AscWaitTixISRDone() which he found necessary to make the
706 driver work with a SCSI-1 disk.
707
708 Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
709 support in the 3.1A driver.
710
711 Doug Gilbert <dgilbert@interlog.com> has made changes and
712 suggestions to improve the driver and done a lot of testing.
713
714 Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
715 in 3.2K.
716
717 Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
718 patch and helped with PowerPC wide and narrow board support.
719
720 Philip Blundell <philb@gnu.org> provided an
721 advansys_interrupts_enabled patch.
722
723 Dave Jones <dave@denial.force9.co.uk> reported the compiler
724 warnings generated when CONFIG_PROC_FS was not defined in
725 the 3.2M driver.
726
727 Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian
728 problems) for wide cards.
729
730 Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow
731 card error handling.
732
733 Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow
734 board support and fixed a bug in AscGetEEPConfig().
735
736 Arnaldo Carvalho de Melo <acme@conectiva.com.br> made
737 save_flags/restore_flags changes.
738
739 Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI
740 driver development for ConnectCom (Version > 3.3F).
741
742 K. ConnectCom (AdvanSys) Contact Information
743
744 Mail: ConnectCom Solutions, Inc.
745 1150 Ringwood Court
746 San Jose, CA 95131
747 Operator/Sales: 1-408-383-9400
748 FAX: 1-408-383-9612
749 Tech Support: 1-408-467-2930
750 Tech Support E-Mail: linux@connectcom.net
751 FTP Site: ftp.connectcom.net (login: anonymous)
752 Web Site: http://www.connectcom.net
753
754*/
755
756/*
757 * --- Linux Include Files
758 */
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761#include <linux/string.h>
762#include <linux/kernel.h>
763#include <linux/types.h>
764#include <linux/ioport.h>
765#include <linux/interrupt.h>
766#include <linux/delay.h>
767#include <linux/slab.h>
768#include <linux/mm.h>
769#include <linux/proc_fs.h>
770#include <linux/init.h>
771#include <linux/blkdev.h>
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -0400772#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773#include <linux/spinlock.h>
774#include <linux/dma-mapping.h>
775
776#include <asm/io.h>
777#include <asm/system.h>
778#include <asm/dma.h>
779
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -0400780#include <scsi/scsi_cmnd.h>
781#include <scsi/scsi_device.h>
782#include <scsi/scsi_tcq.h>
783#include <scsi/scsi.h>
784#include <scsi/scsi_host.h>
785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786/* FIXME: (by jejb@steeleye.com) This warning is present for two
787 * reasons:
788 *
789 * 1) This driver badly needs converting to the correct driver model
790 * probing API
791 *
792 * 2) Although all of the necessary command mapping places have the
793 * appropriate dma_map.. APIs, the driver still processes its internal
794 * queue using bus_to_virt() and virt_to_bus() which are illegal under
795 * the API. The entire queue processing structure will need to be
796 * altered to fix this.
797 */
798#warning this driver is still not properly converted to the DMA API
799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800/*
801 * --- Driver Options
802 */
803
804/* Enable driver assertions. */
805#define ADVANSYS_ASSERT
806
807/* Enable driver /proc statistics. */
808#define ADVANSYS_STATS
809
810/* Enable driver tracing. */
811/* #define ADVANSYS_DEBUG */
812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813/*
814 * --- Asc Library Constants and Macros
815 */
816
817#define ASC_LIB_VERSION_MAJOR 1
818#define ASC_LIB_VERSION_MINOR 24
819#define ASC_LIB_SERIAL_NUMBER 123
820
821/*
822 * Portable Data Types
823 *
824 * Any instance where a 32-bit long or pointer type is assumed
825 * for precision or HW defined structures, the following define
826 * types must be used. In Linux the char, short, and int types
827 * are all consistent at 8, 16, and 32 bits respectively. Pointers
828 * and long types are 64 bits on Alpha and UltraSPARC.
829 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400830#define ASC_PADDR __u32 /* Physical/Bus address data type. */
831#define ASC_VADDR __u32 /* Virtual address data type. */
832#define ASC_DCNT __u32 /* Unsigned Data count type. */
833#define ASC_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834
835/*
836 * These macros are used to convert a virtual address to a
837 * 32-bit value. This currently can be used on Linux Alpha
838 * which uses 64-bit virtual address but a 32-bit bus address.
839 * This is likely to break in the future, but doing this now
840 * will give us time to change the HW and FW to handle 64-bit
841 * addresses.
842 */
843#define ASC_VADDR_TO_U32 virt_to_bus
844#define ASC_U32_TO_VADDR bus_to_virt
845
846typedef unsigned char uchar;
847
848#ifndef TRUE
849#define TRUE (1)
850#endif
851#ifndef FALSE
852#define FALSE (0)
853#endif
854
855#define EOF (-1)
856#define ERR (-1)
857#define UW_ERR (uint)(0xFFFF)
858#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0)
859#define AscPCIConfigVendorIDRegister 0x0000
860#define AscPCIConfigDeviceIDRegister 0x0002
861#define AscPCIConfigCommandRegister 0x0004
862#define AscPCIConfigStatusRegister 0x0006
863#define AscPCIConfigRevisionIDRegister 0x0008
864#define AscPCIConfigCacheSize 0x000C
865#define AscPCIConfigLatencyTimer 0x000D
866#define AscPCIIOBaseRegister 0x0010
867#define AscPCICmdRegBits_IOMemBusMaster 0x0007
868#define ASC_PCI_ID2BUS(id) ((id) & 0xFF)
869#define ASC_PCI_ID2DEV(id) (((id) >> 11) & 0x1F)
870#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
871#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872#define ASC_PCI_REVISION_3150 0x02
873#define ASC_PCI_REVISION_3050 0x03
874
875#define ASC_DVCLIB_CALL_DONE (1)
876#define ASC_DVCLIB_CALL_FAILED (0)
877#define ASC_DVCLIB_CALL_ERROR (-1)
878
Dave Jones2672ea82006-08-02 17:11:49 -0400879#define PCI_VENDOR_ID_ASP 0x10cd
880#define PCI_DEVICE_ID_ASP_1200A 0x1100
881#define PCI_DEVICE_ID_ASP_ABP940 0x1200
882#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
883#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
884#define PCI_DEVICE_ID_38C0800_REV1 0x2500
885#define PCI_DEVICE_ID_38C1600_REV1 0x2700
886
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887/*
888 * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
889 * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
890 * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
891 * SRB structure.
892 */
893#define CC_VERY_LONG_SG_LIST 0
894#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
895
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400896#define PortAddr unsigned short /* port address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897#define inp(port) inb(port)
898#define outp(port, byte) outb((byte), (port))
899
900#define inpw(port) inw(port)
901#define outpw(port, word) outw((word), (port))
902
903#define ASC_MAX_SG_QUEUE 7
904#define ASC_MAX_SG_LIST 255
905
906#define ASC_CS_TYPE unsigned short
907
908#define ASC_IS_ISA (0x0001)
909#define ASC_IS_ISAPNP (0x0081)
910#define ASC_IS_EISA (0x0002)
911#define ASC_IS_PCI (0x0004)
912#define ASC_IS_PCI_ULTRA (0x0104)
913#define ASC_IS_PCMCIA (0x0008)
914#define ASC_IS_MCA (0x0020)
915#define ASC_IS_VL (0x0040)
916#define ASC_ISA_PNP_PORT_ADDR (0x279)
917#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
918#define ASC_IS_WIDESCSI_16 (0x0100)
919#define ASC_IS_WIDESCSI_32 (0x0200)
920#define ASC_IS_BIG_ENDIAN (0x8000)
921#define ASC_CHIP_MIN_VER_VL (0x01)
922#define ASC_CHIP_MAX_VER_VL (0x07)
923#define ASC_CHIP_MIN_VER_PCI (0x09)
924#define ASC_CHIP_MAX_VER_PCI (0x0F)
925#define ASC_CHIP_VER_PCI_BIT (0x08)
926#define ASC_CHIP_MIN_VER_ISA (0x11)
927#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
928#define ASC_CHIP_MAX_VER_ISA (0x27)
929#define ASC_CHIP_VER_ISA_BIT (0x30)
930#define ASC_CHIP_VER_ISAPNP_BIT (0x20)
931#define ASC_CHIP_VER_ASYN_BUG (0x21)
932#define ASC_CHIP_VER_PCI 0x08
933#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02)
934#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03)
935#define ASC_CHIP_MIN_VER_EISA (0x41)
936#define ASC_CHIP_MAX_VER_EISA (0x47)
937#define ASC_CHIP_VER_EISA_BIT (0x40)
938#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
939#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21
940#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A
941#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL)
942#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
943#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL)
944#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
945#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL)
946#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
947#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
948#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
949
950#define ASC_SCSI_ID_BITS 3
951#define ASC_SCSI_TIX_TYPE uchar
952#define ASC_ALL_DEVICE_BIT_SET 0xFF
953#define ASC_SCSI_BIT_ID_TYPE uchar
954#define ASC_MAX_TID 7
955#define ASC_MAX_LUN 7
956#define ASC_SCSI_WIDTH_BIT_SET 0xFF
957#define ASC_MAX_SENSE_LEN 32
958#define ASC_MIN_SENSE_LEN 14
959#define ASC_MAX_CDB_LEN 12
960#define ASC_SCSI_RESET_HOLD_TIME_US 60
961
962#define ADV_INQ_CLOCKING_ST_ONLY 0x0
963#define ADV_INQ_CLOCKING_DT_ONLY 0x1
964#define ADV_INQ_CLOCKING_ST_AND_DT 0x3
965
966/*
967 * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
968 * and CmdDt (Command Support Data) field bit definitions.
969 */
970#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3
971#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2
972#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1
973#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0
974
975#define ASC_SCSIDIR_NOCHK 0x00
976#define ASC_SCSIDIR_T2H 0x08
977#define ASC_SCSIDIR_H2T 0x10
978#define ASC_SCSIDIR_NODATA 0x18
979#define SCSI_ASC_NOMEDIA 0x3A
980#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
981#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
982#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
983#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8))
984#define MS_CMD_DONE 0x00
985#define MS_EXTEND 0x01
986#define MS_SDTR_LEN 0x03
987#define MS_SDTR_CODE 0x01
988#define MS_WDTR_LEN 0x02
989#define MS_WDTR_CODE 0x03
990#define MS_MDP_LEN 0x05
991#define MS_MDP_CODE 0x00
992
993/*
994 * Inquiry data structure and bitfield macros
995 *
996 * Only quantities of more than 1 bit are shifted, since the others are
997 * just tested for true or false. C bitfields aren't portable between big
998 * and little-endian platforms so they are not used.
999 */
1000
1001#define ASC_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
1002#define ASC_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
1003#define ASC_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
1004#define ASC_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
1005#define ASC_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
1006#define ASC_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
1007#define ASC_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
1008#define ASC_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
1009#define ASC_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
1010#define ASC_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
1011#define ASC_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
1012#define ASC_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
1013#define ASC_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
1014#define ASC_INQ_SYNC(inq) ((inq)->flags & 0x10)
1015#define ASC_INQ_WIDE16(inq) ((inq)->flags & 0x20)
1016#define ASC_INQ_WIDE32(inq) ((inq)->flags & 0x40)
1017#define ASC_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
1018#define ASC_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
1019#define ASC_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
1020#define ASC_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
1021
1022typedef struct {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001023 uchar periph;
1024 uchar devtype;
1025 uchar ver;
1026 uchar byte3;
1027 uchar add_len;
1028 uchar res1;
1029 uchar res2;
1030 uchar flags;
1031 uchar vendor_id[8];
1032 uchar product_id[16];
1033 uchar product_rev_level[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034} ASC_SCSI_INQUIRY;
1035
1036#define ASC_SG_LIST_PER_Q 7
1037#define QS_FREE 0x00
1038#define QS_READY 0x01
1039#define QS_DISC1 0x02
1040#define QS_DISC2 0x04
1041#define QS_BUSY 0x08
1042#define QS_ABORTED 0x40
1043#define QS_DONE 0x80
1044#define QC_NO_CALLBACK 0x01
1045#define QC_SG_SWAP_QUEUE 0x02
1046#define QC_SG_HEAD 0x04
1047#define QC_DATA_IN 0x08
1048#define QC_DATA_OUT 0x10
1049#define QC_URGENT 0x20
1050#define QC_MSG_OUT 0x40
1051#define QC_REQ_SENSE 0x80
1052#define QCSG_SG_XFER_LIST 0x02
1053#define QCSG_SG_XFER_MORE 0x04
1054#define QCSG_SG_XFER_END 0x08
1055#define QD_IN_PROGRESS 0x00
1056#define QD_NO_ERROR 0x01
1057#define QD_ABORTED_BY_HOST 0x02
1058#define QD_WITH_ERROR 0x04
1059#define QD_INVALID_REQUEST 0x80
1060#define QD_INVALID_HOST_NUM 0x81
1061#define QD_INVALID_DEVICE 0x82
1062#define QD_ERR_INTERNAL 0xFF
1063#define QHSTA_NO_ERROR 0x00
1064#define QHSTA_M_SEL_TIMEOUT 0x11
1065#define QHSTA_M_DATA_OVER_RUN 0x12
1066#define QHSTA_M_DATA_UNDER_RUN 0x12
1067#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
1068#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
1069#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
1070#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
1071#define QHSTA_D_HOST_ABORT_FAILED 0x23
1072#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
1073#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
1074#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
1075#define QHSTA_M_WTM_TIMEOUT 0x41
1076#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
1077#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
1078#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
1079#define QHSTA_M_TARGET_STATUS_BUSY 0x45
1080#define QHSTA_M_BAD_TAG_CODE 0x46
1081#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
1082#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
1083#define QHSTA_D_LRAM_CMP_ERROR 0x81
1084#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
1085#define ASC_FLAG_SCSIQ_REQ 0x01
1086#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02
1087#define ASC_FLAG_BIOS_ASYNC_IO 0x04
1088#define ASC_FLAG_SRB_LINEAR_ADDR 0x08
1089#define ASC_FLAG_WIN16 0x10
1090#define ASC_FLAG_WIN32 0x20
1091#define ASC_FLAG_ISA_OVER_16MB 0x40
1092#define ASC_FLAG_DOS_VM_CALLBACK 0x80
1093#define ASC_TAG_FLAG_EXTRA_BYTES 0x10
1094#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04
1095#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
1096#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
1097#define ASC_SCSIQ_CPY_BEG 4
1098#define ASC_SCSIQ_SGHD_CPY_BEG 2
1099#define ASC_SCSIQ_B_FWD 0
1100#define ASC_SCSIQ_B_BWD 1
1101#define ASC_SCSIQ_B_STATUS 2
1102#define ASC_SCSIQ_B_QNO 3
1103#define ASC_SCSIQ_B_CNTL 4
1104#define ASC_SCSIQ_B_SG_QUEUE_CNT 5
1105#define ASC_SCSIQ_D_DATA_ADDR 8
1106#define ASC_SCSIQ_D_DATA_CNT 12
1107#define ASC_SCSIQ_B_SENSE_LEN 20
1108#define ASC_SCSIQ_DONE_INFO_BEG 22
1109#define ASC_SCSIQ_D_SRBPTR 22
1110#define ASC_SCSIQ_B_TARGET_IX 26
1111#define ASC_SCSIQ_B_CDB_LEN 28
1112#define ASC_SCSIQ_B_TAG_CODE 29
1113#define ASC_SCSIQ_W_VM_ID 30
1114#define ASC_SCSIQ_DONE_STATUS 32
1115#define ASC_SCSIQ_HOST_STATUS 33
1116#define ASC_SCSIQ_SCSI_STATUS 34
1117#define ASC_SCSIQ_CDB_BEG 36
1118#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
1119#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
1120#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
1121#define ASC_SCSIQ_B_SG_WK_QP 49
1122#define ASC_SCSIQ_B_SG_WK_IX 50
1123#define ASC_SCSIQ_W_ALT_DC1 52
1124#define ASC_SCSIQ_B_LIST_CNT 6
1125#define ASC_SCSIQ_B_CUR_LIST_CNT 7
1126#define ASC_SGQ_B_SG_CNTL 4
1127#define ASC_SGQ_B_SG_HEAD_QP 5
1128#define ASC_SGQ_B_SG_LIST_CNT 6
1129#define ASC_SGQ_B_SG_CUR_LIST_CNT 7
1130#define ASC_SGQ_LIST_BEG 8
1131#define ASC_DEF_SCSI1_QNG 4
1132#define ASC_MAX_SCSI1_QNG 4
1133#define ASC_DEF_SCSI2_QNG 16
1134#define ASC_MAX_SCSI2_QNG 32
1135#define ASC_TAG_CODE_MASK 0x23
1136#define ASC_STOP_REQ_RISC_STOP 0x01
1137#define ASC_STOP_ACK_RISC_STOP 0x03
1138#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10
1139#define ASC_STOP_CLEAN_UP_DISC_Q 0x20
1140#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
1141#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
1142#define ASC_TID_TO_TARGET_ID(tid) (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
1143#define ASC_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ASC_MAX_TID))
1144#define ASC_TIX_TO_TID(tix) ((tix) & ASC_MAX_TID)
1145#define ASC_TID_TO_TIX(tid) ((tid) & ASC_MAX_TID)
1146#define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
1147#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
1148
1149typedef struct asc_scsiq_1 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001150 uchar status;
1151 uchar q_no;
1152 uchar cntl;
1153 uchar sg_queue_cnt;
1154 uchar target_id;
1155 uchar target_lun;
1156 ASC_PADDR data_addr;
1157 ASC_DCNT data_cnt;
1158 ASC_PADDR sense_addr;
1159 uchar sense_len;
1160 uchar extra_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161} ASC_SCSIQ_1;
1162
1163typedef struct asc_scsiq_2 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001164 ASC_VADDR srb_ptr;
1165 uchar target_ix;
1166 uchar flag;
1167 uchar cdb_len;
1168 uchar tag_code;
1169 ushort vm_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170} ASC_SCSIQ_2;
1171
1172typedef struct asc_scsiq_3 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001173 uchar done_stat;
1174 uchar host_stat;
1175 uchar scsi_stat;
1176 uchar scsi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177} ASC_SCSIQ_3;
1178
1179typedef struct asc_scsiq_4 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001180 uchar cdb[ASC_MAX_CDB_LEN];
1181 uchar y_first_sg_list_qp;
1182 uchar y_working_sg_qp;
1183 uchar y_working_sg_ix;
1184 uchar y_res;
1185 ushort x_req_count;
1186 ushort x_reconnect_rtn;
1187 ASC_PADDR x_saved_data_addr;
1188 ASC_DCNT x_saved_data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189} ASC_SCSIQ_4;
1190
1191typedef struct asc_q_done_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001192 ASC_SCSIQ_2 d2;
1193 ASC_SCSIQ_3 d3;
1194 uchar q_status;
1195 uchar q_no;
1196 uchar cntl;
1197 uchar sense_len;
1198 uchar extra_bytes;
1199 uchar res;
1200 ASC_DCNT remain_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201} ASC_QDONE_INFO;
1202
1203typedef struct asc_sg_list {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001204 ASC_PADDR addr;
1205 ASC_DCNT bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206} ASC_SG_LIST;
1207
1208typedef struct asc_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001209 ushort entry_cnt;
1210 ushort queue_cnt;
1211 ushort entry_to_copy;
1212 ushort res;
1213 ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214} ASC_SG_HEAD;
1215
1216#define ASC_MIN_SG_LIST 2
1217
1218typedef struct asc_min_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001219 ushort entry_cnt;
1220 ushort queue_cnt;
1221 ushort entry_to_copy;
1222 ushort res;
1223 ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224} ASC_MIN_SG_HEAD;
1225
1226#define QCX_SORT (0x0001)
1227#define QCX_COALEASE (0x0002)
1228
1229typedef struct asc_scsi_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001230 ASC_SCSIQ_1 q1;
1231 ASC_SCSIQ_2 q2;
1232 uchar *cdbptr;
1233 ASC_SG_HEAD *sg_head;
1234 ushort remain_sg_entry_cnt;
1235 ushort next_sg_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236} ASC_SCSI_Q;
1237
1238typedef struct asc_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001239 ASC_SCSIQ_1 r1;
1240 ASC_SCSIQ_2 r2;
1241 uchar *cdbptr;
1242 ASC_SG_HEAD *sg_head;
1243 uchar *sense_ptr;
1244 ASC_SCSIQ_3 r3;
1245 uchar cdb[ASC_MAX_CDB_LEN];
1246 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247} ASC_SCSI_REQ_Q;
1248
1249typedef struct asc_scsi_bios_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001250 ASC_SCSIQ_1 r1;
1251 ASC_SCSIQ_2 r2;
1252 uchar *cdbptr;
1253 ASC_SG_HEAD *sg_head;
1254 uchar *sense_ptr;
1255 ASC_SCSIQ_3 r3;
1256 uchar cdb[ASC_MAX_CDB_LEN];
1257 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258} ASC_SCSI_BIOS_REQ_Q;
1259
1260typedef struct asc_risc_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001261 uchar fwd;
1262 uchar bwd;
1263 ASC_SCSIQ_1 i1;
1264 ASC_SCSIQ_2 i2;
1265 ASC_SCSIQ_3 i3;
1266 ASC_SCSIQ_4 i4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267} ASC_RISC_Q;
1268
1269typedef struct asc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001270 uchar seq_no;
1271 uchar q_no;
1272 uchar cntl;
1273 uchar sg_head_qp;
1274 uchar sg_list_cnt;
1275 uchar sg_cur_list_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276} ASC_SG_LIST_Q;
1277
1278typedef struct asc_risc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001279 uchar fwd;
1280 uchar bwd;
1281 ASC_SG_LIST_Q sg;
1282 ASC_SG_LIST sg_list[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283} ASC_RISC_SG_LIST_Q;
1284
1285#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
1286#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024
1287#define ASCQ_ERR_NO_ERROR 0
1288#define ASCQ_ERR_IO_NOT_FOUND 1
1289#define ASCQ_ERR_LOCAL_MEM 2
1290#define ASCQ_ERR_CHKSUM 3
1291#define ASCQ_ERR_START_CHIP 4
1292#define ASCQ_ERR_INT_TARGET_ID 5
1293#define ASCQ_ERR_INT_LOCAL_MEM 6
1294#define ASCQ_ERR_HALT_RISC 7
1295#define ASCQ_ERR_GET_ASPI_ENTRY 8
1296#define ASCQ_ERR_CLOSE_ASPI 9
1297#define ASCQ_ERR_HOST_INQUIRY 0x0A
1298#define ASCQ_ERR_SAVED_SRB_BAD 0x0B
1299#define ASCQ_ERR_QCNTL_SG_LIST 0x0C
1300#define ASCQ_ERR_Q_STATUS 0x0D
1301#define ASCQ_ERR_WR_SCSIQ 0x0E
1302#define ASCQ_ERR_PC_ADDR 0x0F
1303#define ASCQ_ERR_SYN_OFFSET 0x10
1304#define ASCQ_ERR_SYN_XFER_TIME 0x11
1305#define ASCQ_ERR_LOCK_DMA 0x12
1306#define ASCQ_ERR_UNLOCK_DMA 0x13
1307#define ASCQ_ERR_VDS_CHK_INSTALL 0x14
1308#define ASCQ_ERR_MICRO_CODE_HALT 0x15
1309#define ASCQ_ERR_SET_LRAM_ADDR 0x16
1310#define ASCQ_ERR_CUR_QNG 0x17
1311#define ASCQ_ERR_SG_Q_LINKS 0x18
1312#define ASCQ_ERR_SCSIQ_PTR 0x19
1313#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
1314#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
1315#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
1316#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D
1317#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
1318#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F
1319#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20
1320#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21
1321#define ASCQ_ERR_SEND_SCSI_Q 0x22
1322#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23
1323#define ASCQ_ERR_RESET_SDTR 0x24
1324
1325/*
1326 * Warning code values are set in ASC_DVC_VAR 'warn_code'.
1327 */
1328#define ASC_WARN_NO_ERROR 0x0000
1329#define ASC_WARN_IO_PORT_ROTATE 0x0001
1330#define ASC_WARN_EEPROM_CHKSUM 0x0002
1331#define ASC_WARN_IRQ_MODIFIED 0x0004
1332#define ASC_WARN_AUTO_CONFIG 0x0008
1333#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
1334#define ASC_WARN_EEPROM_RECOVER 0x0020
1335#define ASC_WARN_CFG_MSW_RECOVER 0x0040
1336#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
1337
1338/*
1339 * Error code values are set in ASC_DVC_VAR 'err_code'.
1340 */
1341#define ASC_IERR_WRITE_EEPROM 0x0001
1342#define ASC_IERR_MCODE_CHKSUM 0x0002
1343#define ASC_IERR_SET_PC_ADDR 0x0004
1344#define ASC_IERR_START_STOP_CHIP 0x0008
1345#define ASC_IERR_IRQ_NO 0x0010
1346#define ASC_IERR_SET_IRQ_NO 0x0020
1347#define ASC_IERR_CHIP_VERSION 0x0040
1348#define ASC_IERR_SET_SCSI_ID 0x0080
1349#define ASC_IERR_GET_PHY_ADDR 0x0100
1350#define ASC_IERR_BAD_SIGNATURE 0x0200
1351#define ASC_IERR_NO_BUS_TYPE 0x0400
1352#define ASC_IERR_SCAM 0x0800
1353#define ASC_IERR_SET_SDTR 0x1000
1354#define ASC_IERR_RW_LRAM 0x8000
1355
1356#define ASC_DEF_IRQ_NO 10
1357#define ASC_MAX_IRQ_NO 15
1358#define ASC_MIN_IRQ_NO 10
1359#define ASC_MIN_REMAIN_Q (0x02)
1360#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
1361#define ASC_MIN_TAG_Q_PER_DVC (0x04)
1362#define ASC_DEF_TAG_Q_PER_DVC (0x04)
1363#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q
1364#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
1365#define ASC_MAX_TOTAL_QNG 240
1366#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
1367#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
1368#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
1369#define ASC_MAX_INRAM_TAG_QNG 16
1370#define ASC_IOADR_TABLE_MAX_IX 11
1371#define ASC_IOADR_GAP 0x10
1372#define ASC_SEARCH_IOP_GAP 0x10
1373#define ASC_MIN_IOP_ADDR (PortAddr)0x0100
1374#define ASC_MAX_IOP_ADDR (PortAddr)0x3F0
1375#define ASC_IOADR_1 (PortAddr)0x0110
1376#define ASC_IOADR_2 (PortAddr)0x0130
1377#define ASC_IOADR_3 (PortAddr)0x0150
1378#define ASC_IOADR_4 (PortAddr)0x0190
1379#define ASC_IOADR_5 (PortAddr)0x0210
1380#define ASC_IOADR_6 (PortAddr)0x0230
1381#define ASC_IOADR_7 (PortAddr)0x0250
1382#define ASC_IOADR_8 (PortAddr)0x0330
1383#define ASC_IOADR_DEF ASC_IOADR_8
1384#define ASC_LIB_SCSIQ_WK_SP 256
1385#define ASC_MAX_SYN_XFER_NO 16
1386#define ASC_SYN_MAX_OFFSET 0x0F
1387#define ASC_DEF_SDTR_OFFSET 0x0F
1388#define ASC_DEF_SDTR_INDEX 0x00
1389#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
1390#define SYN_XFER_NS_0 25
1391#define SYN_XFER_NS_1 30
1392#define SYN_XFER_NS_2 35
1393#define SYN_XFER_NS_3 40
1394#define SYN_XFER_NS_4 50
1395#define SYN_XFER_NS_5 60
1396#define SYN_XFER_NS_6 70
1397#define SYN_XFER_NS_7 85
1398#define SYN_ULTRA_XFER_NS_0 12
1399#define SYN_ULTRA_XFER_NS_1 19
1400#define SYN_ULTRA_XFER_NS_2 25
1401#define SYN_ULTRA_XFER_NS_3 32
1402#define SYN_ULTRA_XFER_NS_4 38
1403#define SYN_ULTRA_XFER_NS_5 44
1404#define SYN_ULTRA_XFER_NS_6 50
1405#define SYN_ULTRA_XFER_NS_7 57
1406#define SYN_ULTRA_XFER_NS_8 63
1407#define SYN_ULTRA_XFER_NS_9 69
1408#define SYN_ULTRA_XFER_NS_10 75
1409#define SYN_ULTRA_XFER_NS_11 82
1410#define SYN_ULTRA_XFER_NS_12 88
1411#define SYN_ULTRA_XFER_NS_13 94
1412#define SYN_ULTRA_XFER_NS_14 100
1413#define SYN_ULTRA_XFER_NS_15 107
1414
1415typedef struct ext_msg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001416 uchar msg_type;
1417 uchar msg_len;
1418 uchar msg_req;
1419 union {
1420 struct {
1421 uchar sdtr_xfer_period;
1422 uchar sdtr_req_ack_offset;
1423 } sdtr;
1424 struct {
1425 uchar wdtr_width;
1426 } wdtr;
1427 struct {
1428 uchar mdp_b3;
1429 uchar mdp_b2;
1430 uchar mdp_b1;
1431 uchar mdp_b0;
1432 } mdp;
1433 } u_ext_msg;
1434 uchar res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435} EXT_MSG;
1436
1437#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
1438#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
1439#define wdtr_width u_ext_msg.wdtr.wdtr_width
1440#define mdp_b3 u_ext_msg.mdp_b3
1441#define mdp_b2 u_ext_msg.mdp_b2
1442#define mdp_b1 u_ext_msg.mdp_b1
1443#define mdp_b0 u_ext_msg.mdp_b0
1444
1445typedef struct asc_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001446 ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
1447 ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
1448 ASC_SCSI_BIT_ID_TYPE disc_enable;
1449 ASC_SCSI_BIT_ID_TYPE sdtr_enable;
1450 uchar chip_scsi_id;
1451 uchar isa_dma_speed;
1452 uchar isa_dma_channel;
1453 uchar chip_version;
1454 ushort lib_serial_no;
1455 ushort lib_version;
1456 ushort mcode_date;
1457 ushort mcode_version;
1458 uchar max_tag_qng[ASC_MAX_TID + 1];
1459 uchar *overrun_buf;
1460 uchar sdtr_period_offset[ASC_MAX_TID + 1];
1461 ushort pci_slot_info;
1462 uchar adapter_info[6];
1463 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464} ASC_DVC_CFG;
1465
1466#define ASC_DEF_DVC_CNTL 0xFFFF
1467#define ASC_DEF_CHIP_SCSI_ID 7
1468#define ASC_DEF_ISA_DMA_SPEED 4
1469#define ASC_INIT_STATE_NULL 0x0000
1470#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
1471#define ASC_INIT_STATE_END_GET_CFG 0x0002
1472#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
1473#define ASC_INIT_STATE_END_SET_CFG 0x0008
1474#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
1475#define ASC_INIT_STATE_END_LOAD_MC 0x0020
1476#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
1477#define ASC_INIT_STATE_END_INQUIRY 0x0080
1478#define ASC_INIT_RESET_SCSI_DONE 0x0100
1479#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
1481#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
1482#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
1483#define ASC_MIN_TAGGED_CMD 7
1484#define ASC_MAX_SCSI_RESET_WAIT 30
1485
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001486struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001488typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
1489typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
1491typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001492 PortAddr iop_base;
1493 ushort err_code;
1494 ushort dvc_cntl;
1495 ushort bug_fix_cntl;
1496 ushort bus_type;
1497 ASC_ISR_CALLBACK isr_callback;
1498 ASC_EXE_CALLBACK exe_callback;
1499 ASC_SCSI_BIT_ID_TYPE init_sdtr;
1500 ASC_SCSI_BIT_ID_TYPE sdtr_done;
1501 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
1502 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
1503 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
1504 ASC_SCSI_BIT_ID_TYPE start_motor;
1505 uchar scsi_reset_wait;
1506 uchar chip_no;
1507 char is_in_int;
1508 uchar max_total_qng;
1509 uchar cur_total_qng;
1510 uchar in_critical_cnt;
1511 uchar irq_no;
1512 uchar last_q_shortage;
1513 ushort init_state;
1514 uchar cur_dvc_qng[ASC_MAX_TID + 1];
1515 uchar max_dvc_qng[ASC_MAX_TID + 1];
1516 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
1517 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
1518 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
1519 ASC_DVC_CFG *cfg;
1520 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
1521 char redo_scam;
1522 ushort res2;
1523 uchar dos_int13_table[ASC_MAX_TID + 1];
1524 ASC_DCNT max_dma_count;
1525 ASC_SCSI_BIT_ID_TYPE no_scam;
1526 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
1527 uchar max_sdtr_index;
1528 uchar host_init_sdtr_index;
1529 struct asc_board *drv_ptr;
1530 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531} ASC_DVC_VAR;
1532
1533typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001534 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535} ASC_DVC_INQ_INFO;
1536
1537typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001538 ASC_DCNT lba;
1539 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540} ASC_CAP_INFO;
1541
1542typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001543 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544} ASC_CAP_INFO_ARRAY;
1545
1546#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
1547#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
1548#define ASC_CNTL_INITIATOR (ushort)0x0001
1549#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
1550#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
1551#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
1552#define ASC_CNTL_NO_SCAM (ushort)0x0010
1553#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
1554#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
1555#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
1556#define ASC_CNTL_RESET_SCSI (ushort)0x0200
1557#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
1558#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
1559#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
1560#define ASC_CNTL_BURST_MODE (ushort)0x2000
1561#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
1562#define ASC_EEP_DVC_CFG_BEG_VL 2
1563#define ASC_EEP_MAX_DVC_ADDR_VL 15
1564#define ASC_EEP_DVC_CFG_BEG 32
1565#define ASC_EEP_MAX_DVC_ADDR 45
1566#define ASC_EEP_DEFINED_WORDS 10
1567#define ASC_EEP_MAX_ADDR 63
1568#define ASC_EEP_RES_WORDS 0
1569#define ASC_EEP_MAX_RETRY 20
1570#define ASC_MAX_INIT_BUSY_RETRY 8
1571#define ASC_EEP_ISA_PNP_WSIZE 16
1572
1573/*
1574 * These macros keep the chip SCSI id and ISA DMA speed
1575 * bitfields in board order. C bitfields aren't portable
1576 * between big and little-endian platforms so they are
1577 * not used.
1578 */
1579
1580#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
1581#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
1582#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
1583 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
1584#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
1585 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
1586
1587typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001588 ushort cfg_lsw;
1589 ushort cfg_msw;
1590 uchar init_sdtr;
1591 uchar disc_enable;
1592 uchar use_cmd_qng;
1593 uchar start_motor;
1594 uchar max_total_qng;
1595 uchar max_tag_qng;
1596 uchar bios_scan;
1597 uchar power_up_wait;
1598 uchar no_scam;
1599 uchar id_speed; /* low order 4 bits is chip scsi id */
1600 /* high order 4 bits is isa dma speed */
1601 uchar dos_int13_table[ASC_MAX_TID + 1];
1602 uchar adapter_info[6];
1603 ushort cntl;
1604 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605} ASCEEP_CONFIG;
1606
1607#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
1608#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
1609#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
1610
1611#define ASC_EEP_CMD_READ 0x80
1612#define ASC_EEP_CMD_WRITE 0x40
1613#define ASC_EEP_CMD_WRITE_ABLE 0x30
1614#define ASC_EEP_CMD_WRITE_DISABLE 0x00
1615#define ASC_OVERRUN_BSIZE 0x00000048UL
1616#define ASC_CTRL_BREAK_ONCE 0x0001
1617#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
1618#define ASCV_MSGOUT_BEG 0x0000
1619#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
1620#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
1621#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
1622#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
1623#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
1624#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
1625#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
1626#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
1627#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
1628#define ASCV_BREAK_ADDR (ushort)0x0028
1629#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
1630#define ASCV_BREAK_CONTROL (ushort)0x002C
1631#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
1632
1633#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
1634#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
1635#define ASCV_MCODE_SIZE_W (ushort)0x0034
1636#define ASCV_STOP_CODE_B (ushort)0x0036
1637#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
1638#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
1639#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
1640#define ASCV_HALTCODE_W (ushort)0x0040
1641#define ASCV_CHKSUM_W (ushort)0x0042
1642#define ASCV_MC_DATE_W (ushort)0x0044
1643#define ASCV_MC_VER_W (ushort)0x0046
1644#define ASCV_NEXTRDY_B (ushort)0x0048
1645#define ASCV_DONENEXT_B (ushort)0x0049
1646#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
1647#define ASCV_SCSIBUSY_B (ushort)0x004B
1648#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
1649#define ASCV_CURCDB_B (ushort)0x004D
1650#define ASCV_RCLUN_B (ushort)0x004E
1651#define ASCV_BUSY_QHEAD_B (ushort)0x004F
1652#define ASCV_DISC1_QHEAD_B (ushort)0x0050
1653#define ASCV_DISC_ENABLE_B (ushort)0x0052
1654#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
1655#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
1656#define ASCV_MCODE_CNTL_B (ushort)0x0056
1657#define ASCV_NULL_TARGET_B (ushort)0x0057
1658#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
1659#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
1660#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
1661#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
1662#define ASCV_HOST_FLAG_B (ushort)0x005D
1663#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
1664#define ASCV_VER_SERIAL_B (ushort)0x0065
1665#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
1666#define ASCV_WTM_FLAG_B (ushort)0x0068
1667#define ASCV_RISC_FLAG_B (ushort)0x006A
1668#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
1669#define ASC_HOST_FLAG_IN_ISR 0x01
1670#define ASC_HOST_FLAG_ACK_INT 0x02
1671#define ASC_RISC_FLAG_GEN_INT 0x01
1672#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
1673#define IOP_CTRL (0x0F)
1674#define IOP_STATUS (0x0E)
1675#define IOP_INT_ACK IOP_STATUS
1676#define IOP_REG_IFC (0x0D)
1677#define IOP_SYN_OFFSET (0x0B)
1678#define IOP_EXTRA_CONTROL (0x0D)
1679#define IOP_REG_PC (0x0C)
1680#define IOP_RAM_ADDR (0x0A)
1681#define IOP_RAM_DATA (0x08)
1682#define IOP_EEP_DATA (0x06)
1683#define IOP_EEP_CMD (0x07)
1684#define IOP_VERSION (0x03)
1685#define IOP_CONFIG_HIGH (0x04)
1686#define IOP_CONFIG_LOW (0x02)
1687#define IOP_SIG_BYTE (0x01)
1688#define IOP_SIG_WORD (0x00)
1689#define IOP_REG_DC1 (0x0E)
1690#define IOP_REG_DC0 (0x0C)
1691#define IOP_REG_SB (0x0B)
1692#define IOP_REG_DA1 (0x0A)
1693#define IOP_REG_DA0 (0x08)
1694#define IOP_REG_SC (0x09)
1695#define IOP_DMA_SPEED (0x07)
1696#define IOP_REG_FLAG (0x07)
1697#define IOP_FIFO_H (0x06)
1698#define IOP_FIFO_L (0x04)
1699#define IOP_REG_ID (0x05)
1700#define IOP_REG_QP (0x03)
1701#define IOP_REG_IH (0x02)
1702#define IOP_REG_IX (0x01)
1703#define IOP_REG_AX (0x00)
1704#define IFC_REG_LOCK (0x00)
1705#define IFC_REG_UNLOCK (0x09)
1706#define IFC_WR_EN_FILTER (0x10)
1707#define IFC_RD_NO_EEPROM (0x10)
1708#define IFC_SLEW_RATE (0x20)
1709#define IFC_ACT_NEG (0x40)
1710#define IFC_INP_FILTER (0x80)
1711#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
1712#define SC_SEL (uchar)(0x80)
1713#define SC_BSY (uchar)(0x40)
1714#define SC_ACK (uchar)(0x20)
1715#define SC_REQ (uchar)(0x10)
1716#define SC_ATN (uchar)(0x08)
1717#define SC_IO (uchar)(0x04)
1718#define SC_CD (uchar)(0x02)
1719#define SC_MSG (uchar)(0x01)
1720#define SEC_SCSI_CTL (uchar)(0x80)
1721#define SEC_ACTIVE_NEGATE (uchar)(0x40)
1722#define SEC_SLEW_RATE (uchar)(0x20)
1723#define SEC_ENABLE_FILTER (uchar)(0x10)
1724#define ASC_HALT_EXTMSG_IN (ushort)0x8000
1725#define ASC_HALT_CHK_CONDITION (ushort)0x8100
1726#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
1727#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
1728#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
1729#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
1730#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
1731#define ASC_MAX_QNO 0xF8
1732#define ASC_DATA_SEC_BEG (ushort)0x0080
1733#define ASC_DATA_SEC_END (ushort)0x0080
1734#define ASC_CODE_SEC_BEG (ushort)0x0080
1735#define ASC_CODE_SEC_END (ushort)0x0080
1736#define ASC_QADR_BEG (0x4000)
1737#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
1738#define ASC_QADR_END (ushort)0x7FFF
1739#define ASC_QLAST_ADR (ushort)0x7FC0
1740#define ASC_QBLK_SIZE 0x40
1741#define ASC_BIOS_DATA_QBEG 0xF8
1742#define ASC_MIN_ACTIVE_QNO 0x01
1743#define ASC_QLINK_END 0xFF
1744#define ASC_EEPROM_WORDS 0x10
1745#define ASC_MAX_MGS_LEN 0x10
1746#define ASC_BIOS_ADDR_DEF 0xDC00
1747#define ASC_BIOS_SIZE 0x3800
1748#define ASC_BIOS_RAM_OFF 0x3800
1749#define ASC_BIOS_RAM_SIZE 0x800
1750#define ASC_BIOS_MIN_ADDR 0xC000
1751#define ASC_BIOS_MAX_ADDR 0xEC00
1752#define ASC_BIOS_BANK_SIZE 0x0400
1753#define ASC_MCODE_START_ADDR 0x0080
1754#define ASC_CFG0_HOST_INT_ON 0x0020
1755#define ASC_CFG0_BIOS_ON 0x0040
1756#define ASC_CFG0_VERA_BURST_ON 0x0080
1757#define ASC_CFG0_SCSI_PARITY_ON 0x0800
1758#define ASC_CFG1_SCSI_TARGET_ON 0x0080
1759#define ASC_CFG1_LRAM_8BITS_ON 0x0800
1760#define ASC_CFG_MSW_CLR_MASK 0x3080
1761#define CSW_TEST1 (ASC_CS_TYPE)0x8000
1762#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
1763#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
1764#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
1765#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
1766#define CSW_TEST2 (ASC_CS_TYPE)0x0400
1767#define CSW_TEST3 (ASC_CS_TYPE)0x0200
1768#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
1769#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
1770#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
1771#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
1772#define CSW_HALTED (ASC_CS_TYPE)0x0010
1773#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
1774#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
1775#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
1776#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
1777#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
1778#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
1779#define CIW_TEST1 (ASC_CS_TYPE)0x0200
1780#define CIW_TEST2 (ASC_CS_TYPE)0x0400
1781#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
1782#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
1783#define CC_CHIP_RESET (uchar)0x80
1784#define CC_SCSI_RESET (uchar)0x40
1785#define CC_HALT (uchar)0x20
1786#define CC_SINGLE_STEP (uchar)0x10
1787#define CC_DMA_ABLE (uchar)0x08
1788#define CC_TEST (uchar)0x04
1789#define CC_BANK_ONE (uchar)0x02
1790#define CC_DIAG (uchar)0x01
1791#define ASC_1000_ID0W 0x04C1
1792#define ASC_1000_ID0W_FIX 0x00C1
1793#define ASC_1000_ID1B 0x25
1794#define ASC_EISA_BIG_IOP_GAP (0x1C30-0x0C50)
1795#define ASC_EISA_SMALL_IOP_GAP (0x0020)
1796#define ASC_EISA_MIN_IOP_ADDR (0x0C30)
1797#define ASC_EISA_MAX_IOP_ADDR (0xFC50)
1798#define ASC_EISA_REV_IOP_MASK (0x0C83)
1799#define ASC_EISA_PID_IOP_MASK (0x0C80)
1800#define ASC_EISA_CFG_IOP_MASK (0x0C86)
1801#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
1802#define ASC_EISA_ID_740 0x01745004UL
1803#define ASC_EISA_ID_750 0x01755004UL
1804#define INS_HALTINT (ushort)0x6281
1805#define INS_HALT (ushort)0x6280
1806#define INS_SINT (ushort)0x6200
1807#define INS_RFLAG_WTM (ushort)0x7380
1808#define ASC_MC_SAVE_CODE_WSIZE 0x500
1809#define ASC_MC_SAVE_DATA_WSIZE 0x40
1810
1811typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001812 ushort data[ASC_MC_SAVE_DATA_WSIZE];
1813 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814} ASC_MC_SAVED;
1815
1816#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
1817#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
1818#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
1819#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
1820#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
1821#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
1822#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
1823#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
1824#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
1825#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
1826#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
1827#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
1828#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
1829#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
1830#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
1831#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
1832#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
1833#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
1834#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
1835#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
1836#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
1837#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
1838#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
1839#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
1840#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
1841#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
1842#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
1843#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
1844#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
1845#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
1846#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
1847#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
1848#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
1849#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
1850#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
1851#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
1852#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
1853#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
1854#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
1855#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
1856#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
1857#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
1858#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
1859#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
1860#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
1861#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
1862#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
1863#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
1864#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
1865#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
1866#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
1867#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
1868#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
1869#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
1870#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
1871#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
1872#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
1873#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
1874#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
1875#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
1876#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
1877#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
1878#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
1879#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
1880#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
1881#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
1882#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
1883#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
1884
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001885static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
1886static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
1887static void AscWaitEEPRead(void);
1888static void AscWaitEEPWrite(void);
1889static ushort AscReadEEPWord(PortAddr, uchar);
1890static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
1891static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1892static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
1893static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1894static int AscStartChip(PortAddr);
1895static int AscStopChip(PortAddr);
1896static void AscSetChipIH(PortAddr, ushort);
1897static int AscIsChipHalted(PortAddr);
1898static void AscAckInterrupt(PortAddr);
1899static void AscDisableInterrupt(PortAddr);
1900static void AscEnableInterrupt(PortAddr);
1901static void AscSetBank(PortAddr, uchar);
1902static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001904static ushort AscGetIsaDmaChannel(PortAddr);
1905static ushort AscSetIsaDmaChannel(PortAddr, ushort);
1906static uchar AscSetIsaDmaSpeed(PortAddr, uchar);
1907static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001909static uchar AscReadLramByte(PortAddr, ushort);
1910static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001912static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001914static void AscWriteLramWord(PortAddr, ushort, ushort);
1915static void AscWriteLramByte(PortAddr, ushort, uchar);
1916static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
1917static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
1918static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1919static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1920static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
1921static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
1922static ushort AscInitFromEEP(ASC_DVC_VAR *);
1923static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
1924static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1925static int AscTestExternalLram(ASC_DVC_VAR *);
1926static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1927static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1928static void AscSetChipSDTR(PortAddr, uchar, uchar);
1929static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1930static uchar AscAllocFreeQueue(PortAddr, uchar);
1931static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1932static int AscHostReqRiscHalt(PortAddr);
1933static int AscStopQueueExe(PortAddr);
1934static int AscSendScsiQueue(ASC_DVC_VAR *,
1935 ASC_SCSI_Q *scsiq, uchar n_q_required);
1936static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1937static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1938static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1939static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1940static ushort AscInitLram(ASC_DVC_VAR *);
1941static ushort AscInitQLinkVar(ASC_DVC_VAR *);
1942static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1943static int AscIsrChipHalted(ASC_DVC_VAR *);
1944static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1945 ASC_QDONE_INFO *, ASC_DCNT);
1946static int AscIsrQDone(ASC_DVC_VAR *);
1947static int AscCompareString(uchar *, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001949static ushort AscGetEisaChipCfg(PortAddr);
1950static ASC_DCNT AscGetEisaProductID(PortAddr);
1951static PortAddr AscSearchIOPortAddrEISA(PortAddr);
1952static PortAddr AscSearchIOPortAddr11(PortAddr);
1953static PortAddr AscSearchIOPortAddr(PortAddr, ushort);
1954static void AscSetISAPNPWaitForKey(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001956static uchar AscGetChipScsiCtrl(PortAddr);
1957static uchar AscSetChipScsiID(PortAddr, uchar);
1958static uchar AscGetChipVersion(PortAddr, ushort);
1959static ushort AscGetChipBusType(PortAddr);
1960static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
1961static int AscFindSignature(PortAddr);
1962static void AscToggleIRQAct(PortAddr);
1963static uchar AscGetChipIRQ(PortAddr, ushort);
1964static uchar AscSetChipIRQ(PortAddr, uchar, ushort);
1965static ushort AscGetChipBiosAddress(PortAddr, ushort);
1966static inline ulong DvcEnterCritical(void);
1967static inline void DvcLeaveCritical(ulong);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001969static uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
1970static void DvcWritePCIConfigByte(ASC_DVC_VAR *, ushort, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001972static ushort AscGetChipBiosAddress(PortAddr, ushort);
1973static void DvcSleepMilliSecond(ASC_DCNT);
1974static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
1975static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1976static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
1977static ushort AscInitGetConfig(ASC_DVC_VAR *);
1978static ushort AscInitSetConfig(ASC_DVC_VAR *);
1979static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
1980static void AscAsyncFix(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
1981static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
1982static void AscInquiryHandling(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
1983static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1984static int AscISR(ASC_DVC_VAR *);
1985static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1986static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001988static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001990static ASC_DCNT AscGetMaxDmaCount(ushort);
1991static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992
1993/*
1994 * --- Adv Library Constants and Macros
1995 */
1996
1997#define ADV_LIB_VERSION_MAJOR 5
1998#define ADV_LIB_VERSION_MINOR 14
1999
2000/*
2001 * Define Adv Library required special types.
2002 */
2003
2004/*
2005 * Portable Data Types
2006 *
2007 * Any instance where a 32-bit long or pointer type is assumed
2008 * for precision or HW defined structures, the following define
2009 * types must be used. In Linux the char, short, and int types
2010 * are all consistent at 8, 16, and 32 bits respectively. Pointers
2011 * and long types are 64 bits on Alpha and UltraSPARC.
2012 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002013#define ADV_PADDR __u32 /* Physical address data type. */
2014#define ADV_VADDR __u32 /* Virtual address data type. */
2015#define ADV_DCNT __u32 /* Unsigned Data count type. */
2016#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
2018/*
2019 * These macros are used to convert a virtual address to a
2020 * 32-bit value. This currently can be used on Linux Alpha
2021 * which uses 64-bit virtual address but a 32-bit bus address.
2022 * This is likely to break in the future, but doing this now
2023 * will give us time to change the HW and FW to handle 64-bit
2024 * addresses.
2025 */
2026#define ADV_VADDR_TO_U32 virt_to_bus
2027#define ADV_U32_TO_VADDR bus_to_virt
2028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002029#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
2031/*
2032 * Define Adv Library required memory access macros.
2033 */
2034#define ADV_MEM_READB(addr) readb(addr)
2035#define ADV_MEM_READW(addr) readw(addr)
2036#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
2037#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
2038#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
2039
2040#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
2041
2042/*
2043 * For wide boards a CDB length maximum of 16 bytes
2044 * is supported.
2045 */
2046#define ADV_MAX_CDB_LEN 16
2047
2048/*
2049 * Define total number of simultaneous maximum element scatter-gather
2050 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
2051 * maximum number of outstanding commands per wide host adapter. Each
2052 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
2053 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
2054 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
2055 * structures or 255 scatter-gather elements.
2056 *
2057 */
2058#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
2059
2060/*
2061 * Define Adv Library required maximum number of scatter-gather
2062 * elements per request.
2063 */
2064#define ADV_MAX_SG_LIST 255
2065
2066/* Number of SG blocks needed. */
2067#define ADV_NUM_SG_BLOCK \
2068 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
2069
2070/* Total contiguous memory needed for SG blocks. */
2071#define ADV_SG_TOTAL_MEM_SIZE \
2072 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
2073
2074#define ADV_PAGE_SIZE PAGE_SIZE
2075
2076#define ADV_NUM_PAGE_CROSSING \
2077 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2078
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079#define ADV_EEP_DVC_CFG_BEGIN (0x00)
2080#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002081#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082#define ADV_EEP_MAX_WORD_ADDR (0x1E)
2083
2084#define ADV_EEP_DELAY_MS 100
2085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002086#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
2087#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088/*
2089 * For the ASC3550 Bit 13 is Termination Polarity control bit.
2090 * For later ICs Bit 13 controls whether the CIS (Card Information
2091 * Service Section) is loaded from EEPROM.
2092 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002093#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
2094#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095/*
2096 * ASC38C1600 Bit 11
2097 *
2098 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
2099 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
2100 * Function 0 will specify INT B.
2101 *
2102 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
2103 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
2104 * Function 1 will specify INT A.
2105 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002106#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002108typedef struct adveep_3550_config {
2109 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002111 ushort cfg_lsw; /* 00 power up initialization */
2112 /* bit 13 set - Term Polarity Control */
2113 /* bit 14 set - BIOS Enable */
2114 /* bit 15 set - Big Endian Mode */
2115 ushort cfg_msw; /* 01 unused */
2116 ushort disc_enable; /* 02 disconnect enable */
2117 ushort wdtr_able; /* 03 Wide DTR able */
2118 ushort sdtr_able; /* 04 Synchronous DTR able */
2119 ushort start_motor; /* 05 send start up motor */
2120 ushort tagqng_able; /* 06 tag queuing able */
2121 ushort bios_scan; /* 07 BIOS device control */
2122 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002124 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2125 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002127 uchar scsi_reset_delay; /* 10 reset delay */
2128 uchar bios_id_lun; /* first boot device scsi id & lun */
2129 /* high nibble is lun */
2130 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002132 uchar termination; /* 11 0 - automatic */
2133 /* 1 - low off / high off */
2134 /* 2 - low off / high on */
2135 /* 3 - low on / high on */
2136 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002138 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002140 ushort bios_ctrl; /* 12 BIOS control bits */
2141 /* bit 0 BIOS don't act as initiator. */
2142 /* bit 1 BIOS > 1 GB support */
2143 /* bit 2 BIOS > 2 Disk Support */
2144 /* bit 3 BIOS don't support removables */
2145 /* bit 4 BIOS support bootable CD */
2146 /* bit 5 BIOS scan enabled */
2147 /* bit 6 BIOS support multiple LUNs */
2148 /* bit 7 BIOS display of message */
2149 /* bit 8 SCAM disabled */
2150 /* bit 9 Reset SCSI bus during init. */
2151 /* bit 10 */
2152 /* bit 11 No verbose initialization. */
2153 /* bit 12 SCSI parity enabled */
2154 /* bit 13 */
2155 /* bit 14 */
2156 /* bit 15 */
2157 ushort ultra_able; /* 13 ULTRA speed able */
2158 ushort reserved2; /* 14 reserved */
2159 uchar max_host_qng; /* 15 maximum host queuing */
2160 uchar max_dvc_qng; /* maximum per device queuing */
2161 ushort dvc_cntl; /* 16 control bit for driver */
2162 ushort bug_fix; /* 17 control bit for bug fix */
2163 ushort serial_number_word1; /* 18 Board serial number word 1 */
2164 ushort serial_number_word2; /* 19 Board serial number word 2 */
2165 ushort serial_number_word3; /* 20 Board serial number word 3 */
2166 ushort check_sum; /* 21 EEP check sum */
2167 uchar oem_name[16]; /* 22 OEM name */
2168 ushort dvc_err_code; /* 30 last device driver error code */
2169 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2170 ushort adv_err_addr; /* 32 last uc error address */
2171 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2172 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2173 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2174 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175} ADVEEP_3550_CONFIG;
2176
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002177typedef struct adveep_38C0800_config {
2178 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002180 ushort cfg_lsw; /* 00 power up initialization */
2181 /* bit 13 set - Load CIS */
2182 /* bit 14 set - BIOS Enable */
2183 /* bit 15 set - Big Endian Mode */
2184 ushort cfg_msw; /* 01 unused */
2185 ushort disc_enable; /* 02 disconnect enable */
2186 ushort wdtr_able; /* 03 Wide DTR able */
2187 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2188 ushort start_motor; /* 05 send start up motor */
2189 ushort tagqng_able; /* 06 tag queuing able */
2190 ushort bios_scan; /* 07 BIOS device control */
2191 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002193 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2194 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002196 uchar scsi_reset_delay; /* 10 reset delay */
2197 uchar bios_id_lun; /* first boot device scsi id & lun */
2198 /* high nibble is lun */
2199 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002201 uchar termination_se; /* 11 0 - automatic */
2202 /* 1 - low off / high off */
2203 /* 2 - low off / high on */
2204 /* 3 - low on / high on */
2205 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002207 uchar termination_lvd; /* 11 0 - automatic */
2208 /* 1 - low off / high off */
2209 /* 2 - low off / high on */
2210 /* 3 - low on / high on */
2211 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002213 ushort bios_ctrl; /* 12 BIOS control bits */
2214 /* bit 0 BIOS don't act as initiator. */
2215 /* bit 1 BIOS > 1 GB support */
2216 /* bit 2 BIOS > 2 Disk Support */
2217 /* bit 3 BIOS don't support removables */
2218 /* bit 4 BIOS support bootable CD */
2219 /* bit 5 BIOS scan enabled */
2220 /* bit 6 BIOS support multiple LUNs */
2221 /* bit 7 BIOS display of message */
2222 /* bit 8 SCAM disabled */
2223 /* bit 9 Reset SCSI bus during init. */
2224 /* bit 10 */
2225 /* bit 11 No verbose initialization. */
2226 /* bit 12 SCSI parity enabled */
2227 /* bit 13 */
2228 /* bit 14 */
2229 /* bit 15 */
2230 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2231 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2232 uchar max_host_qng; /* 15 maximum host queueing */
2233 uchar max_dvc_qng; /* maximum per device queuing */
2234 ushort dvc_cntl; /* 16 control bit for driver */
2235 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2236 ushort serial_number_word1; /* 18 Board serial number word 1 */
2237 ushort serial_number_word2; /* 19 Board serial number word 2 */
2238 ushort serial_number_word3; /* 20 Board serial number word 3 */
2239 ushort check_sum; /* 21 EEP check sum */
2240 uchar oem_name[16]; /* 22 OEM name */
2241 ushort dvc_err_code; /* 30 last device driver error code */
2242 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2243 ushort adv_err_addr; /* 32 last uc error address */
2244 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2245 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2246 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2247 ushort reserved36; /* 36 reserved */
2248 ushort reserved37; /* 37 reserved */
2249 ushort reserved38; /* 38 reserved */
2250 ushort reserved39; /* 39 reserved */
2251 ushort reserved40; /* 40 reserved */
2252 ushort reserved41; /* 41 reserved */
2253 ushort reserved42; /* 42 reserved */
2254 ushort reserved43; /* 43 reserved */
2255 ushort reserved44; /* 44 reserved */
2256 ushort reserved45; /* 45 reserved */
2257 ushort reserved46; /* 46 reserved */
2258 ushort reserved47; /* 47 reserved */
2259 ushort reserved48; /* 48 reserved */
2260 ushort reserved49; /* 49 reserved */
2261 ushort reserved50; /* 50 reserved */
2262 ushort reserved51; /* 51 reserved */
2263 ushort reserved52; /* 52 reserved */
2264 ushort reserved53; /* 53 reserved */
2265 ushort reserved54; /* 54 reserved */
2266 ushort reserved55; /* 55 reserved */
2267 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2268 ushort cisprt_msw; /* 57 CIS PTR MSW */
2269 ushort subsysvid; /* 58 SubSystem Vendor ID */
2270 ushort subsysid; /* 59 SubSystem ID */
2271 ushort reserved60; /* 60 reserved */
2272 ushort reserved61; /* 61 reserved */
2273 ushort reserved62; /* 62 reserved */
2274 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275} ADVEEP_38C0800_CONFIG;
2276
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002277typedef struct adveep_38C1600_config {
2278 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002280 ushort cfg_lsw; /* 00 power up initialization */
2281 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
2282 /* clear - Func. 0 INTA, Func. 1 INTB */
2283 /* bit 13 set - Load CIS */
2284 /* bit 14 set - BIOS Enable */
2285 /* bit 15 set - Big Endian Mode */
2286 ushort cfg_msw; /* 01 unused */
2287 ushort disc_enable; /* 02 disconnect enable */
2288 ushort wdtr_able; /* 03 Wide DTR able */
2289 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2290 ushort start_motor; /* 05 send start up motor */
2291 ushort tagqng_able; /* 06 tag queuing able */
2292 ushort bios_scan; /* 07 BIOS device control */
2293 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002295 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2296 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002298 uchar scsi_reset_delay; /* 10 reset delay */
2299 uchar bios_id_lun; /* first boot device scsi id & lun */
2300 /* high nibble is lun */
2301 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002303 uchar termination_se; /* 11 0 - automatic */
2304 /* 1 - low off / high off */
2305 /* 2 - low off / high on */
2306 /* 3 - low on / high on */
2307 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002309 uchar termination_lvd; /* 11 0 - automatic */
2310 /* 1 - low off / high off */
2311 /* 2 - low off / high on */
2312 /* 3 - low on / high on */
2313 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002315 ushort bios_ctrl; /* 12 BIOS control bits */
2316 /* bit 0 BIOS don't act as initiator. */
2317 /* bit 1 BIOS > 1 GB support */
2318 /* bit 2 BIOS > 2 Disk Support */
2319 /* bit 3 BIOS don't support removables */
2320 /* bit 4 BIOS support bootable CD */
2321 /* bit 5 BIOS scan enabled */
2322 /* bit 6 BIOS support multiple LUNs */
2323 /* bit 7 BIOS display of message */
2324 /* bit 8 SCAM disabled */
2325 /* bit 9 Reset SCSI bus during init. */
2326 /* bit 10 Basic Integrity Checking disabled */
2327 /* bit 11 No verbose initialization. */
2328 /* bit 12 SCSI parity enabled */
2329 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
2330 /* bit 14 */
2331 /* bit 15 */
2332 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2333 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2334 uchar max_host_qng; /* 15 maximum host queueing */
2335 uchar max_dvc_qng; /* maximum per device queuing */
2336 ushort dvc_cntl; /* 16 control bit for driver */
2337 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2338 ushort serial_number_word1; /* 18 Board serial number word 1 */
2339 ushort serial_number_word2; /* 19 Board serial number word 2 */
2340 ushort serial_number_word3; /* 20 Board serial number word 3 */
2341 ushort check_sum; /* 21 EEP check sum */
2342 uchar oem_name[16]; /* 22 OEM name */
2343 ushort dvc_err_code; /* 30 last device driver error code */
2344 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2345 ushort adv_err_addr; /* 32 last uc error address */
2346 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2347 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2348 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2349 ushort reserved36; /* 36 reserved */
2350 ushort reserved37; /* 37 reserved */
2351 ushort reserved38; /* 38 reserved */
2352 ushort reserved39; /* 39 reserved */
2353 ushort reserved40; /* 40 reserved */
2354 ushort reserved41; /* 41 reserved */
2355 ushort reserved42; /* 42 reserved */
2356 ushort reserved43; /* 43 reserved */
2357 ushort reserved44; /* 44 reserved */
2358 ushort reserved45; /* 45 reserved */
2359 ushort reserved46; /* 46 reserved */
2360 ushort reserved47; /* 47 reserved */
2361 ushort reserved48; /* 48 reserved */
2362 ushort reserved49; /* 49 reserved */
2363 ushort reserved50; /* 50 reserved */
2364 ushort reserved51; /* 51 reserved */
2365 ushort reserved52; /* 52 reserved */
2366 ushort reserved53; /* 53 reserved */
2367 ushort reserved54; /* 54 reserved */
2368 ushort reserved55; /* 55 reserved */
2369 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2370 ushort cisprt_msw; /* 57 CIS PTR MSW */
2371 ushort subsysvid; /* 58 SubSystem Vendor ID */
2372 ushort subsysid; /* 59 SubSystem ID */
2373 ushort reserved60; /* 60 reserved */
2374 ushort reserved61; /* 61 reserved */
2375 ushort reserved62; /* 62 reserved */
2376 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377} ADVEEP_38C1600_CONFIG;
2378
2379/*
2380 * EEPROM Commands
2381 */
2382#define ASC_EEP_CMD_DONE 0x0200
2383#define ASC_EEP_CMD_DONE_ERR 0x0001
2384
2385/* cfg_word */
2386#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
2387
2388/* bios_ctrl */
2389#define BIOS_CTRL_BIOS 0x0001
2390#define BIOS_CTRL_EXTENDED_XLAT 0x0002
2391#define BIOS_CTRL_GT_2_DISK 0x0004
2392#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
2393#define BIOS_CTRL_BOOTABLE_CD 0x0010
2394#define BIOS_CTRL_MULTIPLE_LUN 0x0040
2395#define BIOS_CTRL_DISPLAY_MSG 0x0080
2396#define BIOS_CTRL_NO_SCAM 0x0100
2397#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
2398#define BIOS_CTRL_INIT_VERBOSE 0x0800
2399#define BIOS_CTRL_SCSI_PARITY 0x1000
2400#define BIOS_CTRL_AIPP_DIS 0x2000
2401
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002402#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
2403#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002405#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2406#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
2408/*
2409 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
2410 * a special 16K Adv Library and Microcode version. After the issue is
2411 * resolved, should restore 32K support.
2412 *
2413 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
2414 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002415#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2416#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
2417#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418
2419/*
2420 * Byte I/O register address from base of 'iop_base'.
2421 */
2422#define IOPB_INTR_STATUS_REG 0x00
2423#define IOPB_CHIP_ID_1 0x01
2424#define IOPB_INTR_ENABLES 0x02
2425#define IOPB_CHIP_TYPE_REV 0x03
2426#define IOPB_RES_ADDR_4 0x04
2427#define IOPB_RES_ADDR_5 0x05
2428#define IOPB_RAM_DATA 0x06
2429#define IOPB_RES_ADDR_7 0x07
2430#define IOPB_FLAG_REG 0x08
2431#define IOPB_RES_ADDR_9 0x09
2432#define IOPB_RISC_CSR 0x0A
2433#define IOPB_RES_ADDR_B 0x0B
2434#define IOPB_RES_ADDR_C 0x0C
2435#define IOPB_RES_ADDR_D 0x0D
2436#define IOPB_SOFT_OVER_WR 0x0E
2437#define IOPB_RES_ADDR_F 0x0F
2438#define IOPB_MEM_CFG 0x10
2439#define IOPB_RES_ADDR_11 0x11
2440#define IOPB_GPIO_DATA 0x12
2441#define IOPB_RES_ADDR_13 0x13
2442#define IOPB_FLASH_PAGE 0x14
2443#define IOPB_RES_ADDR_15 0x15
2444#define IOPB_GPIO_CNTL 0x16
2445#define IOPB_RES_ADDR_17 0x17
2446#define IOPB_FLASH_DATA 0x18
2447#define IOPB_RES_ADDR_19 0x19
2448#define IOPB_RES_ADDR_1A 0x1A
2449#define IOPB_RES_ADDR_1B 0x1B
2450#define IOPB_RES_ADDR_1C 0x1C
2451#define IOPB_RES_ADDR_1D 0x1D
2452#define IOPB_RES_ADDR_1E 0x1E
2453#define IOPB_RES_ADDR_1F 0x1F
2454#define IOPB_DMA_CFG0 0x20
2455#define IOPB_DMA_CFG1 0x21
2456#define IOPB_TICKLE 0x22
2457#define IOPB_DMA_REG_WR 0x23
2458#define IOPB_SDMA_STATUS 0x24
2459#define IOPB_SCSI_BYTE_CNT 0x25
2460#define IOPB_HOST_BYTE_CNT 0x26
2461#define IOPB_BYTE_LEFT_TO_XFER 0x27
2462#define IOPB_BYTE_TO_XFER_0 0x28
2463#define IOPB_BYTE_TO_XFER_1 0x29
2464#define IOPB_BYTE_TO_XFER_2 0x2A
2465#define IOPB_BYTE_TO_XFER_3 0x2B
2466#define IOPB_ACC_GRP 0x2C
2467#define IOPB_RES_ADDR_2D 0x2D
2468#define IOPB_DEV_ID 0x2E
2469#define IOPB_RES_ADDR_2F 0x2F
2470#define IOPB_SCSI_DATA 0x30
2471#define IOPB_RES_ADDR_31 0x31
2472#define IOPB_RES_ADDR_32 0x32
2473#define IOPB_SCSI_DATA_HSHK 0x33
2474#define IOPB_SCSI_CTRL 0x34
2475#define IOPB_RES_ADDR_35 0x35
2476#define IOPB_RES_ADDR_36 0x36
2477#define IOPB_RES_ADDR_37 0x37
2478#define IOPB_RAM_BIST 0x38
2479#define IOPB_PLL_TEST 0x39
2480#define IOPB_PCI_INT_CFG 0x3A
2481#define IOPB_RES_ADDR_3B 0x3B
2482#define IOPB_RFIFO_CNT 0x3C
2483#define IOPB_RES_ADDR_3D 0x3D
2484#define IOPB_RES_ADDR_3E 0x3E
2485#define IOPB_RES_ADDR_3F 0x3F
2486
2487/*
2488 * Word I/O register address from base of 'iop_base'.
2489 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002490#define IOPW_CHIP_ID_0 0x00 /* CID0 */
2491#define IOPW_CTRL_REG 0x02 /* CC */
2492#define IOPW_RAM_ADDR 0x04 /* LA */
2493#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002495#define IOPW_RISC_CSR 0x0A /* CSR */
2496#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
2497#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002499#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002501#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002503#define IOPW_EE_CMD 0x1A /* EC */
2504#define IOPW_EE_DATA 0x1C /* ED */
2505#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002507#define IOPW_Q_BASE 0x22 /* QB */
2508#define IOPW_QP 0x24 /* QP */
2509#define IOPW_IX 0x26 /* IX */
2510#define IOPW_SP 0x28 /* SP */
2511#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512#define IOPW_RES_ADDR_2C 0x2C
2513#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002514#define IOPW_SCSI_DATA 0x30 /* SD */
2515#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
2516#define IOPW_SCSI_CTRL 0x34 /* SC */
2517#define IOPW_HSHK_CFG 0x36 /* HCFG */
2518#define IOPW_SXFR_STATUS 0x36 /* SXS */
2519#define IOPW_SXFR_CNTL 0x38 /* SXL */
2520#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002522#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
2524/*
2525 * Doubleword I/O register address from base of 'iop_base'.
2526 */
2527#define IOPDW_RES_ADDR_0 0x00
2528#define IOPDW_RAM_DATA 0x04
2529#define IOPDW_RES_ADDR_8 0x08
2530#define IOPDW_RES_ADDR_C 0x0C
2531#define IOPDW_RES_ADDR_10 0x10
2532#define IOPDW_COMMA 0x14
2533#define IOPDW_COMMB 0x18
2534#define IOPDW_RES_ADDR_1C 0x1C
2535#define IOPDW_SDMA_ADDR0 0x20
2536#define IOPDW_SDMA_ADDR1 0x24
2537#define IOPDW_SDMA_COUNT 0x28
2538#define IOPDW_SDMA_ERROR 0x2C
2539#define IOPDW_RDMA_ADDR0 0x30
2540#define IOPDW_RDMA_ADDR1 0x34
2541#define IOPDW_RDMA_COUNT 0x38
2542#define IOPDW_RDMA_ERROR 0x3C
2543
2544#define ADV_CHIP_ID_BYTE 0x25
2545#define ADV_CHIP_ID_WORD 0x04C1
2546
2547#define ADV_SC_SCSI_BUS_RESET 0x2000
2548
2549#define ADV_INTR_ENABLE_HOST_INTR 0x01
2550#define ADV_INTR_ENABLE_SEL_INTR 0x02
2551#define ADV_INTR_ENABLE_DPR_INTR 0x04
2552#define ADV_INTR_ENABLE_RTA_INTR 0x08
2553#define ADV_INTR_ENABLE_RMA_INTR 0x10
2554#define ADV_INTR_ENABLE_RST_INTR 0x20
2555#define ADV_INTR_ENABLE_DPE_INTR 0x40
2556#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
2557
2558#define ADV_INTR_STATUS_INTRA 0x01
2559#define ADV_INTR_STATUS_INTRB 0x02
2560#define ADV_INTR_STATUS_INTRC 0x04
2561
2562#define ADV_RISC_CSR_STOP (0x0000)
2563#define ADV_RISC_TEST_COND (0x2000)
2564#define ADV_RISC_CSR_RUN (0x4000)
2565#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
2566
2567#define ADV_CTRL_REG_HOST_INTR 0x0100
2568#define ADV_CTRL_REG_SEL_INTR 0x0200
2569#define ADV_CTRL_REG_DPR_INTR 0x0400
2570#define ADV_CTRL_REG_RTA_INTR 0x0800
2571#define ADV_CTRL_REG_RMA_INTR 0x1000
2572#define ADV_CTRL_REG_RES_BIT14 0x2000
2573#define ADV_CTRL_REG_DPE_INTR 0x4000
2574#define ADV_CTRL_REG_POWER_DONE 0x8000
2575#define ADV_CTRL_REG_ANY_INTR 0xFF00
2576
2577#define ADV_CTRL_REG_CMD_RESET 0x00C6
2578#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
2579#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
2580#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
2581#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
2582
2583#define ADV_TICKLE_NOP 0x00
2584#define ADV_TICKLE_A 0x01
2585#define ADV_TICKLE_B 0x02
2586#define ADV_TICKLE_C 0x03
2587
2588#define ADV_SCSI_CTRL_RSTOUT 0x2000
2589
2590#define AdvIsIntPending(port) \
2591 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
2592
2593/*
2594 * SCSI_CFG0 Register bit definitions
2595 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002596#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
2597#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
2598#define EVEN_PARITY 0x1000 /* Select Even Parity */
2599#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
2600#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
2601#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
2602#define SCAM_EN 0x0080 /* Enable SCAM selection */
2603#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
2604#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
2605#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
2606#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
2608/*
2609 * SCSI_CFG1 Register bit definitions
2610 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002611#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
2612#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
2613#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
2614#define FILTER_SEL 0x0C00 /* Filter Period Selection */
2615#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
2616#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
2617#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
2618#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
2619#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
2620#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
2621#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
2622#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
2623#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
2624#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
2625#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626
2627/*
2628 * Addendum for ASC-38C0800 Chip
2629 *
2630 * The ASC-38C1600 Chip uses the same definitions except that the
2631 * bus mode override bits [12:10] have been moved to byte register
2632 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
2633 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
2634 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
2635 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
2636 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
2637 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002638#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
2639#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
2640#define HVD 0x1000 /* HVD Device Detect */
2641#define LVD 0x0800 /* LVD Device Detect */
2642#define SE 0x0400 /* SE Device Detect */
2643#define TERM_LVD 0x00C0 /* LVD Termination Bits */
2644#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
2645#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
2646#define TERM_SE 0x0030 /* SE Termination Bits */
2647#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
2648#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
2649#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
2650#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
2651#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
2652#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
2653#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
2654#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
2656#define CABLE_ILLEGAL_A 0x7
2657 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
2658
2659#define CABLE_ILLEGAL_B 0xB
2660 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
2661
2662/*
2663 * MEM_CFG Register bit definitions
2664 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002665#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
2666#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
2667#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
2668#define RAM_SZ_2KB 0x00 /* 2 KB */
2669#define RAM_SZ_4KB 0x04 /* 4 KB */
2670#define RAM_SZ_8KB 0x08 /* 8 KB */
2671#define RAM_SZ_16KB 0x0C /* 16 KB */
2672#define RAM_SZ_32KB 0x10 /* 32 KB */
2673#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674
2675/*
2676 * DMA_CFG0 Register bit definitions
2677 *
2678 * This register is only accessible to the host.
2679 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002680#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
2681#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
2682#define FIFO_THRESH_16B 0x00 /* 16 bytes */
2683#define FIFO_THRESH_32B 0x20 /* 32 bytes */
2684#define FIFO_THRESH_48B 0x30 /* 48 bytes */
2685#define FIFO_THRESH_64B 0x40 /* 64 bytes */
2686#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
2687#define FIFO_THRESH_96B 0x60 /* 96 bytes */
2688#define FIFO_THRESH_112B 0x70 /* 112 bytes */
2689#define START_CTL 0x0C /* DMA start conditions */
2690#define START_CTL_TH 0x00 /* Wait threshold level (default) */
2691#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
2692#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
2693#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
2694#define READ_CMD 0x03 /* Memory Read Method */
2695#define READ_CMD_MR 0x00 /* Memory Read */
2696#define READ_CMD_MRL 0x02 /* Memory Read Long */
2697#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698
2699/*
2700 * ASC-38C0800 RAM BIST Register bit definitions
2701 */
2702#define RAM_TEST_MODE 0x80
2703#define PRE_TEST_MODE 0x40
2704#define NORMAL_MODE 0x00
2705#define RAM_TEST_DONE 0x10
2706#define RAM_TEST_STATUS 0x0F
2707#define RAM_TEST_HOST_ERROR 0x08
2708#define RAM_TEST_INTRAM_ERROR 0x04
2709#define RAM_TEST_RISC_ERROR 0x02
2710#define RAM_TEST_SCSI_ERROR 0x01
2711#define RAM_TEST_SUCCESS 0x00
2712#define PRE_TEST_VALUE 0x05
2713#define NORMAL_VALUE 0x00
2714
2715/*
2716 * ASC38C1600 Definitions
2717 *
2718 * IOPB_PCI_INT_CFG Bit Field Definitions
2719 */
2720
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002721#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722
2723/*
2724 * Bit 1 can be set to change the interrupt for the Function to operate in
2725 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
2726 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
2727 * mode, otherwise the operating mode is undefined.
2728 */
2729#define TOTEMPOLE 0x02
2730
2731/*
2732 * Bit 0 can be used to change the Int Pin for the Function. The value is
2733 * 0 by default for both Functions with Function 0 using INT A and Function
2734 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
2735 * INT A is used.
2736 *
2737 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
2738 * value specified in the PCI Configuration Space.
2739 */
2740#define INTAB 0x01
2741
2742/* a_advlib.h */
2743
2744/*
2745 * Adv Library Status Definitions
2746 */
2747#define ADV_TRUE 1
2748#define ADV_FALSE 0
2749#define ADV_NOERROR 1
2750#define ADV_SUCCESS 1
2751#define ADV_BUSY 0
2752#define ADV_ERROR (-1)
2753
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754/*
2755 * ADV_DVC_VAR 'warn_code' values
2756 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002757#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
2758#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
2759#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
2760#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
2761#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002763#define ADV_MAX_TID 15 /* max. target identifier */
2764#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765
2766/*
2767 * Error code values are set in ADV_DVC_VAR 'err_code'.
2768 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002769#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
2770#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
2771#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
2772#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
2773#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
2774#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
2775#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
2776#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
2777#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
2778#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
2779#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
2780#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
2781#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
2782#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
2784/*
2785 * Fixed locations of microcode operating variables.
2786 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002787#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
2788#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
2789#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
2790#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
2791#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
2792#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
2793#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
2794#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
2795#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
2796#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
2797#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
2798#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
2799#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800#define ASC_MC_CHIP_TYPE 0x009A
2801#define ASC_MC_INTRB_CODE 0x009B
2802#define ASC_MC_WDTR_ABLE 0x009C
2803#define ASC_MC_SDTR_ABLE 0x009E
2804#define ASC_MC_TAGQNG_ABLE 0x00A0
2805#define ASC_MC_DISC_ENABLE 0x00A2
2806#define ASC_MC_IDLE_CMD_STATUS 0x00A4
2807#define ASC_MC_IDLE_CMD 0x00A6
2808#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
2809#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
2810#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
2811#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
2812#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
2813#define ASC_MC_SDTR_DONE 0x00B6
2814#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
2815#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
2816#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002817#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002819#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820#define ASC_MC_ICQ 0x0160
2821#define ASC_MC_IRQ 0x0164
2822#define ASC_MC_PPR_ABLE 0x017A
2823
2824/*
2825 * BIOS LRAM variable absolute offsets.
2826 */
2827#define BIOS_CODESEG 0x54
2828#define BIOS_CODELEN 0x56
2829#define BIOS_SIGNATURE 0x58
2830#define BIOS_VERSION 0x5A
2831
2832/*
2833 * Microcode Control Flags
2834 *
2835 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
2836 * and handled by the microcode.
2837 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002838#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
2839#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840
2841/*
2842 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
2843 */
2844#define HSHK_CFG_WIDE_XFR 0x8000
2845#define HSHK_CFG_RATE 0x0F00
2846#define HSHK_CFG_OFFSET 0x001F
2847
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002848#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
2849#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
2850#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
2851#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002853#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2854#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2855#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2856#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2857#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002859#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2860#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2861#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2862#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2863#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864/*
2865 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2866 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2867 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002868#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2869#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870
2871/*
2872 * All fields here are accessed by the board microcode and need to be
2873 * little-endian.
2874 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002875typedef struct adv_carr_t {
2876 ADV_VADDR carr_va; /* Carrier Virtual Address */
2877 ADV_PADDR carr_pa; /* Carrier Physical Address */
2878 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2879 /*
2880 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2881 *
2882 * next_vpa [3:1] Reserved Bits
2883 * next_vpa [0] Done Flag set in Response Queue.
2884 */
2885 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886} ADV_CARR_T;
2887
2888/*
2889 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2890 */
2891#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2892
2893#define ASC_RQ_DONE 0x00000001
2894#define ASC_RQ_GOOD 0x00000002
2895#define ASC_CQ_STOPPER 0x00000000
2896
2897#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2898
2899#define ADV_CARRIER_NUM_PAGE_CROSSING \
2900 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2901 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2902
2903#define ADV_CARRIER_BUFSIZE \
2904 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2905
2906/*
2907 * ASC_SCSI_REQ_Q 'a_flag' definitions
2908 *
2909 * The Adv Library should limit use to the lower nibble (4 bits) of
2910 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2911 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002912#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2913#define ADV_SCSIQ_DONE 0x02 /* request done */
2914#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002916#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2917#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2918#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
2920/*
2921 * Adapter temporary configuration structure
2922 *
2923 * This structure can be discarded after initialization. Don't add
2924 * fields here needed after initialization.
2925 *
2926 * Field naming convention:
2927 *
2928 * *_enable indicates the field enables or disables a feature. The
2929 * value of the field is never reset.
2930 */
2931typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002932 ushort disc_enable; /* enable disconnection */
2933 uchar chip_version; /* chip version */
2934 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2935 ushort lib_version; /* Adv Library version number */
2936 ushort control_flag; /* Microcode Control Flag */
2937 ushort mcode_date; /* Microcode date */
2938 ushort mcode_version; /* Microcode version */
2939 ushort pci_slot_info; /* high byte device/function number */
2940 /* bits 7-3 device num., bits 2-0 function num. */
2941 /* low byte bus num. */
2942 ushort serial1; /* EEPROM serial number word 1 */
2943 ushort serial2; /* EEPROM serial number word 2 */
2944 ushort serial3; /* EEPROM serial number word 3 */
2945 struct device *dev; /* pointer to the pci dev structure for this board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946} ADV_DVC_CFG;
2947
2948struct adv_dvc_var;
2949struct adv_scsi_req_q;
2950
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002951typedef void (*ADV_ISR_CALLBACK)
2952 (struct adv_dvc_var *, struct adv_scsi_req_q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002954typedef void (*ADV_ASYNC_CALLBACK)
2955 (struct adv_dvc_var *, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956
2957/*
2958 * Adapter operation variable structure.
2959 *
2960 * One structure is required per host adapter.
2961 *
2962 * Field naming convention:
2963 *
2964 * *_able indicates both whether a feature should be enabled or disabled
2965 * and whether a device isi capable of the feature. At initialization
2966 * this field may be set, but later if a device is found to be incapable
2967 * of the feature, the field is cleared.
2968 */
2969typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002970 AdvPortAddr iop_base; /* I/O port address */
2971 ushort err_code; /* fatal error code */
2972 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
2973 ADV_ISR_CALLBACK isr_callback;
2974 ADV_ASYNC_CALLBACK async_callback;
2975 ushort wdtr_able; /* try WDTR for a device */
2976 ushort sdtr_able; /* try SDTR for a device */
2977 ushort ultra_able; /* try SDTR Ultra speed for a device */
2978 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2979 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2980 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2981 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2982 ushort tagqng_able; /* try tagged queuing with a device */
2983 ushort ppr_able; /* PPR message capable per TID bitmask. */
2984 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2985 ushort start_motor; /* start motor command allowed */
2986 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2987 uchar chip_no; /* should be assigned by caller */
2988 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2989 uchar irq_no; /* IRQ number */
2990 ushort no_scam; /* scam_tolerant of EEPROM */
2991 struct asc_board *drv_ptr; /* driver pointer to private structure */
2992 uchar chip_scsi_id; /* chip SCSI target ID */
2993 uchar chip_type;
2994 uchar bist_err_code;
2995 ADV_CARR_T *carrier_buf;
2996 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2997 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2998 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2999 ushort carr_pending_cnt; /* Count of pending carriers. */
3000 /*
3001 * Note: The following fields will not be used after initialization. The
3002 * driver may discard the buffer after initialization is done.
3003 */
3004 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005} ADV_DVC_VAR;
3006
3007#define NO_OF_SG_PER_BLOCK 15
3008
3009typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003010 uchar reserved1;
3011 uchar reserved2;
3012 uchar reserved3;
3013 uchar sg_cnt; /* Valid entries in block. */
3014 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
3015 struct {
3016 ADV_PADDR sg_addr; /* SG element address. */
3017 ADV_DCNT sg_count; /* SG element count. */
3018 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019} ADV_SG_BLOCK;
3020
3021/*
3022 * ADV_SCSI_REQ_Q - microcode request structure
3023 *
3024 * All fields in this structure up to byte 60 are used by the microcode.
3025 * The microcode makes assumptions about the size and ordering of fields
3026 * in this structure. Do not change the structure definition here without
3027 * coordinating the change with the microcode.
3028 *
3029 * All fields accessed by microcode must be maintained in little_endian
3030 * order.
3031 */
3032typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003033 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
3034 uchar target_cmd;
3035 uchar target_id; /* Device target identifier. */
3036 uchar target_lun; /* Device target logical unit number. */
3037 ADV_PADDR data_addr; /* Data buffer physical address. */
3038 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
3039 ADV_PADDR sense_addr;
3040 ADV_PADDR carr_pa;
3041 uchar mflag;
3042 uchar sense_len;
3043 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
3044 uchar scsi_cntl;
3045 uchar done_status; /* Completion status. */
3046 uchar scsi_status; /* SCSI status byte. */
3047 uchar host_status; /* Ucode host status. */
3048 uchar sg_working_ix;
3049 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
3050 ADV_PADDR sg_real_addr; /* SG list physical address. */
3051 ADV_PADDR scsiq_rptr;
3052 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
3053 ADV_VADDR scsiq_ptr;
3054 ADV_VADDR carr_va;
3055 /*
3056 * End of microcode structure - 60 bytes. The rest of the structure
3057 * is used by the Adv Library and ignored by the microcode.
3058 */
3059 ADV_VADDR srb_ptr;
3060 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
3061 char *vdata_addr; /* Data buffer virtual address. */
3062 uchar a_flag;
3063 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064} ADV_SCSI_REQ_Q;
3065
3066/*
3067 * Microcode idle loop commands
3068 */
3069#define IDLE_CMD_COMPLETED 0
3070#define IDLE_CMD_STOP_CHIP 0x0001
3071#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
3072#define IDLE_CMD_SEND_INT 0x0004
3073#define IDLE_CMD_ABORT 0x0008
3074#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003075#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
3076#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077#define IDLE_CMD_SCSIREQ 0x0080
3078
3079#define IDLE_CMD_STATUS_SUCCESS 0x0001
3080#define IDLE_CMD_STATUS_FAILURE 0x0002
3081
3082/*
3083 * AdvSendIdleCmd() flag definitions.
3084 */
3085#define ADV_NOWAIT 0x01
3086
3087/*
3088 * Wait loop time out values.
3089 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003090#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
3091#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
3092#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
3093#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
3094#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003096#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
3097#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
3098#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
3099#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003101#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102
3103/*
3104 * Device drivers must define the following functions.
3105 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003106static inline ulong DvcEnterCritical(void);
3107static inline void DvcLeaveCritical(ulong);
3108static void DvcSleepMilliSecond(ADV_DCNT);
3109static uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
3110static void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
3111static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
3112 uchar *, ASC_SDCNT *, int);
3113static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
3115/*
3116 * Adv Library functions available to drivers.
3117 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003118static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3119static int AdvISR(ADV_DVC_VAR *);
3120static int AdvInitGetConfig(ADV_DVC_VAR *);
3121static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
3122static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
3123static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
3124static int AdvResetChipAndSB(ADV_DVC_VAR *);
3125static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126
3127/*
3128 * Internal Adv Library functions.
3129 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003130static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
3131static void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3132static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
3133static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
3134static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
3135static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3136static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3137static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3138static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3139static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3140static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3141static void AdvWaitEEPCmd(AdvPortAddr);
3142static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143
3144/*
3145 * PCI Bus Definitions
3146 */
3147#define AscPCICmdRegBits_BusMastering 0x0007
3148#define AscPCICmdRegBits_ParErrRespCtrl 0x0040
3149
3150/* Read byte from a register. */
3151#define AdvReadByteRegister(iop_base, reg_off) \
3152 (ADV_MEM_READB((iop_base) + (reg_off)))
3153
3154/* Write byte to a register. */
3155#define AdvWriteByteRegister(iop_base, reg_off, byte) \
3156 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
3157
3158/* Read word (2 bytes) from a register. */
3159#define AdvReadWordRegister(iop_base, reg_off) \
3160 (ADV_MEM_READW((iop_base) + (reg_off)))
3161
3162/* Write word (2 bytes) to a register. */
3163#define AdvWriteWordRegister(iop_base, reg_off, word) \
3164 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
3165
3166/* Write dword (4 bytes) to a register. */
3167#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
3168 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
3169
3170/* Read byte from LRAM. */
3171#define AdvReadByteLram(iop_base, addr, byte) \
3172do { \
3173 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3174 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
3175} while (0)
3176
3177/* Write byte to LRAM. */
3178#define AdvWriteByteLram(iop_base, addr, byte) \
3179 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3180 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
3181
3182/* Read word (2 bytes) from LRAM. */
3183#define AdvReadWordLram(iop_base, addr, word) \
3184do { \
3185 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3186 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
3187} while (0)
3188
3189/* Write word (2 bytes) to LRAM. */
3190#define AdvWriteWordLram(iop_base, addr, word) \
3191 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3192 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3193
3194/* Write little-endian double word (4 bytes) to LRAM */
3195/* Because of unspecified C language ordering don't use auto-increment. */
3196#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
3197 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3198 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3199 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
3200 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
3201 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3202 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
3203
3204/* Read word (2 bytes) from LRAM assuming that the address is already set. */
3205#define AdvReadWordAutoIncLram(iop_base) \
3206 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
3207
3208/* Write word (2 bytes) to LRAM assuming that the address is already set. */
3209#define AdvWriteWordAutoIncLram(iop_base, word) \
3210 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3211
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212/*
3213 * Define macro to check for Condor signature.
3214 *
3215 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
3216 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
3217 */
3218#define AdvFindSignature(iop_base) \
3219 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
3220 ADV_CHIP_ID_BYTE) && \
3221 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
3222 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
3223
3224/*
3225 * Define macro to Return the version number of the chip at 'iop_base'.
3226 *
3227 * The second parameter 'bus_type' is currently unused.
3228 */
3229#define AdvGetChipVersion(iop_base, bus_type) \
3230 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
3231
3232/*
3233 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
3234 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
3235 *
3236 * If the request has not yet been sent to the device it will simply be
3237 * aborted from RISC memory. If the request is disconnected it will be
3238 * aborted on reselection by sending an Abort Message to the target ID.
3239 *
3240 * Return value:
3241 * ADV_TRUE(1) - Queue was successfully aborted.
3242 * ADV_FALSE(0) - Queue was not found on the active queue list.
3243 */
3244#define AdvAbortQueue(asc_dvc, scsiq) \
3245 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
3246 (ADV_DCNT) (scsiq))
3247
3248/*
3249 * Send a Bus Device Reset Message to the specified target ID.
3250 *
3251 * All outstanding commands will be purged if sending the
3252 * Bus Device Reset Message is successful.
3253 *
3254 * Return Value:
3255 * ADV_TRUE(1) - All requests on the target are purged.
3256 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
3257 * are not purged.
3258 */
3259#define AdvResetDevice(asc_dvc, target_id) \
3260 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
3261 (ADV_DCNT) (target_id))
3262
3263/*
3264 * SCSI Wide Type definition.
3265 */
3266#define ADV_SCSI_BIT_ID_TYPE ushort
3267
3268/*
3269 * AdvInitScsiTarget() 'cntl_flag' options.
3270 */
3271#define ADV_SCAN_LUN 0x01
3272#define ADV_CAPINFO_NOLUN 0x02
3273
3274/*
3275 * Convert target id to target id bit mask.
3276 */
3277#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
3278
3279/*
3280 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
3281 */
3282
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003283#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284#define QD_NO_ERROR 0x01
3285#define QD_ABORTED_BY_HOST 0x02
3286#define QD_WITH_ERROR 0x04
3287
3288#define QHSTA_NO_ERROR 0x00
3289#define QHSTA_M_SEL_TIMEOUT 0x11
3290#define QHSTA_M_DATA_OVER_RUN 0x12
3291#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
3292#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003293#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
3294#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
3295#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
3296#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
3297#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
3298#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
3299#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003301#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
3302#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
3303#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
3304#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
3305#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
3306#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
3307#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
3308#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309#define QHSTA_M_WTM_TIMEOUT 0x41
3310#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
3311#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
3312#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003313#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
3314#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
3315#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316
3317/*
3318 * Default EEPROM Configuration structure defined in a_init.c.
3319 */
3320static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
3321static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
3322static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
3323
3324/*
3325 * DvcGetPhyAddr() flag arguments
3326 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003327#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
3328#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
3329#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
3330#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
3331#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
3332#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333
3334/* Return the address that is aligned at the next doubleword >= to 'addr'. */
3335#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
3336#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
3337#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
3338
3339/*
3340 * Total contiguous memory needed for driver SG blocks.
3341 *
3342 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
3343 * number of scatter-gather elements the driver supports in a
3344 * single request.
3345 */
3346
3347#define ADV_SG_LIST_MAX_BYTE_SIZE \
3348 (sizeof(ADV_SG_BLOCK) * \
3349 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
3350
3351/*
3352 * Inquiry data structure and bitfield macros
3353 *
3354 * Using bitfields to access the subchar data isn't portable across
3355 * endianness, so instead mask and shift. Only quantities of more
3356 * than 1 bit are shifted, since the others are just tested for true
3357 * or false.
3358 */
3359
3360#define ADV_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
3361#define ADV_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
3362#define ADV_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
3363#define ADV_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
3364#define ADV_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
3365#define ADV_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
3366#define ADV_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
3367#define ADV_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
3368#define ADV_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
3369#define ADV_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
3370#define ADV_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
3371#define ADV_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
3372#define ADV_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
3373#define ADV_INQ_SYNC(inq) ((inq)->flags & 0x10)
3374#define ADV_INQ_WIDE16(inq) ((inq)->flags & 0x20)
3375#define ADV_INQ_WIDE32(inq) ((inq)->flags & 0x40)
3376#define ADV_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
3377#define ADV_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
3378#define ADV_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
3379#define ADV_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
3380
3381typedef struct {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003382 uchar periph; /* peripheral device type [0:4] */
3383 /* peripheral qualifier [5:7] */
3384 uchar devtype; /* device type modifier (for SCSI I) [0:6] */
3385 /* RMB - removable medium bit [7] */
3386 uchar ver; /* ANSI approved version [0:2] */
3387 /* ECMA version [3:5] */
3388 /* ISO version [6:7] */
3389 uchar byte3; /* response data format [0:3] */
3390 /* 0 SCSI 1 */
3391 /* 1 CCS */
3392 /* 2 SCSI-2 */
3393 /* 3-F reserved */
3394 /* reserved [4:5] */
3395 /* terminate I/O process bit (see 5.6.22) [6] */
3396 /* asynch. event notification (processor) [7] */
3397 uchar add_len; /* additional length */
3398 uchar res1; /* reserved */
3399 uchar res2; /* reserved */
3400 uchar flags; /* soft reset implemented [0] */
3401 /* command queuing [1] */
3402 /* reserved [2] */
3403 /* linked command for this logical unit [3] */
3404 /* synchronous data transfer [4] */
3405 /* wide bus 16 bit data transfer [5] */
3406 /* wide bus 32 bit data transfer [6] */
3407 /* relative addressing mode [7] */
3408 uchar vendor_id[8]; /* vendor identification */
3409 uchar product_id[16]; /* product identification */
3410 uchar product_rev_level[4]; /* product revision level */
3411 uchar vendor_specific[20]; /* vendor specific */
3412 uchar info; /* information unit supported [0] */
3413 /* quick arbitrate supported [1] */
3414 /* clocking field [2:3] */
3415 /* reserved [4:7] */
3416 uchar res3; /* reserved */
3417} ADV_SCSI_INQUIRY; /* 58 bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418
3419/*
3420 * --- Driver Constants and Macros
3421 */
3422
3423#define ASC_NUM_BOARD_SUPPORTED 16
3424#define ASC_NUM_IOPORT_PROBE 4
3425#define ASC_NUM_BUS 4
3426
3427/* Reference Scsi_Host hostdata */
3428#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
3429
3430/* asc_board_t flags */
3431#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003432#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433#define ASC_SELECT_QUEUE_DEPTHS 0x08
3434
3435#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
3436#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
3437
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003438#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003440#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441
3442#ifdef CONFIG_PROC_FS
3443/* /proc/scsi/advansys/[0...] related definitions */
3444#define ASC_PRTBUF_SIZE 2048
3445#define ASC_PRTLINE_SIZE 160
3446
3447#define ASC_PRT_NEXT() \
3448 if (cp) { \
3449 totlen += len; \
3450 leftlen -= len; \
3451 if (leftlen == 0) { \
3452 return totlen; \
3453 } \
3454 cp += len; \
3455 }
3456#endif /* CONFIG_PROC_FS */
3457
3458/* Asc Library return codes */
3459#define ASC_TRUE 1
3460#define ASC_FALSE 0
3461#define ASC_NOERROR 1
3462#define ASC_BUSY 0
3463#define ASC_ERROR (-1)
3464
3465/* struct scsi_cmnd function return codes */
3466#define STATUS_BYTE(byte) (byte)
3467#define MSG_BYTE(byte) ((byte) << 8)
3468#define HOST_BYTE(byte) ((byte) << 16)
3469#define DRIVER_BYTE(byte) ((byte) << 24)
3470
3471/*
3472 * The following definitions and macros are OS independent interfaces to
3473 * the queue functions:
3474 * REQ - SCSI request structure
3475 * REQP - pointer to SCSI request structure
3476 * REQPTID(reqp) - reqp's target id
3477 * REQPNEXT(reqp) - reqp's next pointer
3478 * REQPNEXTP(reqp) - pointer to reqp's next pointer
3479 * REQPTIME(reqp) - reqp's time stamp value
3480 * REQTIMESTAMP() - system time stamp value
3481 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003482typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
3484#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
3485#define REQPTID(reqp) ((reqp)->device->id)
3486#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
3487#define REQTIMESTAMP() (jiffies)
3488
3489#define REQTIMESTAT(function, ascq, reqp, tid) \
3490{ \
3491 /*
3492 * If the request time stamp is less than the system time stamp, then \
3493 * maybe the system time stamp wrapped. Set the request time to zero.\
3494 */ \
3495 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
3496 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
3497 } else { \
3498 /* Indicate an error occurred with the assertion. */ \
3499 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
3500 REQPTIME(reqp) = 0; \
3501 } \
3502 /* Handle first minimum time case without external initialization. */ \
3503 if (((ascq)->q_tot_cnt[tid] == 1) || \
3504 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
3505 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
3506 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
3507 (function), (tid), (ascq)->q_min_tim[tid]); \
3508 } \
3509 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
3510 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
3511 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
3512 (function), tid, (ascq)->q_max_tim[tid]); \
3513 } \
3514 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
3515 /* Reset the time stamp field. */ \
3516 REQPTIME(reqp) = 0; \
3517}
3518
3519/* asc_enqueue() flags */
3520#define ASC_FRONT 1
3521#define ASC_BACK 2
3522
3523/* asc_dequeue_list() argument */
3524#define ASC_TID_ALL (-1)
3525
3526/* Return non-zero, if the queue is empty. */
3527#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
3528
3529#define PCI_MAX_SLOT 0x1F
3530#define PCI_MAX_BUS 0xFF
3531#define PCI_IOADDRESS_MASK 0xFFFE
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003532#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533
3534#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003535#define ASC_STATS(shost, counter)
3536#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003538#define ASC_STATS(shost, counter) \
3539 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003541#define ASC_STATS_ADD(shost, counter, count) \
3542 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543#endif /* ADVANSYS_STATS */
3544
3545#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
3546
3547/* If the result wraps when calculating tenths, return 0. */
3548#define ASC_TENTHS(num, den) \
3549 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
3550 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
3551
3552/*
3553 * Display a message to the console.
3554 */
3555#define ASC_PRINT(s) \
3556 { \
3557 printk("advansys: "); \
3558 printk(s); \
3559 }
3560
3561#define ASC_PRINT1(s, a1) \
3562 { \
3563 printk("advansys: "); \
3564 printk((s), (a1)); \
3565 }
3566
3567#define ASC_PRINT2(s, a1, a2) \
3568 { \
3569 printk("advansys: "); \
3570 printk((s), (a1), (a2)); \
3571 }
3572
3573#define ASC_PRINT3(s, a1, a2, a3) \
3574 { \
3575 printk("advansys: "); \
3576 printk((s), (a1), (a2), (a3)); \
3577 }
3578
3579#define ASC_PRINT4(s, a1, a2, a3, a4) \
3580 { \
3581 printk("advansys: "); \
3582 printk((s), (a1), (a2), (a3), (a4)); \
3583 }
3584
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585#ifndef ADVANSYS_DEBUG
3586
3587#define ASC_DBG(lvl, s)
3588#define ASC_DBG1(lvl, s, a1)
3589#define ASC_DBG2(lvl, s, a1, a2)
3590#define ASC_DBG3(lvl, s, a1, a2, a3)
3591#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
3592#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
3593#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
3594#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
3595#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3596#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
3597#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3598#define ASC_DBG_PRT_HEX(lvl, name, start, length)
3599#define ASC_DBG_PRT_CDB(lvl, cdb, len)
3600#define ASC_DBG_PRT_SENSE(lvl, sense, len)
3601#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
3602
3603#else /* ADVANSYS_DEBUG */
3604
3605/*
3606 * Debugging Message Levels:
3607 * 0: Errors Only
3608 * 1: High-Level Tracing
3609 * 2-N: Verbose Tracing
3610 */
3611
3612#define ASC_DBG(lvl, s) \
3613 { \
3614 if (asc_dbglvl >= (lvl)) { \
3615 printk(s); \
3616 } \
3617 }
3618
3619#define ASC_DBG1(lvl, s, a1) \
3620 { \
3621 if (asc_dbglvl >= (lvl)) { \
3622 printk((s), (a1)); \
3623 } \
3624 }
3625
3626#define ASC_DBG2(lvl, s, a1, a2) \
3627 { \
3628 if (asc_dbglvl >= (lvl)) { \
3629 printk((s), (a1), (a2)); \
3630 } \
3631 }
3632
3633#define ASC_DBG3(lvl, s, a1, a2, a3) \
3634 { \
3635 if (asc_dbglvl >= (lvl)) { \
3636 printk((s), (a1), (a2), (a3)); \
3637 } \
3638 }
3639
3640#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
3641 { \
3642 if (asc_dbglvl >= (lvl)) { \
3643 printk((s), (a1), (a2), (a3), (a4)); \
3644 } \
3645 }
3646
3647#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
3648 { \
3649 if (asc_dbglvl >= (lvl)) { \
3650 asc_prt_scsi_host(s); \
3651 } \
3652 }
3653
3654#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
3655 { \
3656 if (asc_dbglvl >= (lvl)) { \
3657 asc_prt_scsi_cmnd(s); \
3658 } \
3659 }
3660
3661#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
3662 { \
3663 if (asc_dbglvl >= (lvl)) { \
3664 asc_prt_asc_scsi_q(scsiqp); \
3665 } \
3666 }
3667
3668#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
3669 { \
3670 if (asc_dbglvl >= (lvl)) { \
3671 asc_prt_asc_qdone_info(qdone); \
3672 } \
3673 }
3674
3675#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
3676 { \
3677 if (asc_dbglvl >= (lvl)) { \
3678 asc_prt_adv_scsi_req_q(scsiqp); \
3679 } \
3680 }
3681
3682#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
3683 { \
3684 if (asc_dbglvl >= (lvl)) { \
3685 asc_prt_hex((name), (start), (length)); \
3686 } \
3687 }
3688
3689#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
3690 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
3691
3692#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
3693 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
3694
3695#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
3696 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
3697#endif /* ADVANSYS_DEBUG */
3698
3699#ifndef ADVANSYS_ASSERT
3700#define ASC_ASSERT(a)
3701#else /* ADVANSYS_ASSERT */
3702
3703#define ASC_ASSERT(a) \
3704 { \
3705 if (!(a)) { \
3706 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
3707 __FILE__, __LINE__); \
3708 } \
3709 }
3710
3711#endif /* ADVANSYS_ASSERT */
3712
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713/*
3714 * --- Driver Structures
3715 */
3716
3717#ifdef ADVANSYS_STATS
3718
3719/* Per board statistics structure */
3720struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003721 /* Driver Entrypoint Statistics */
3722 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
3723 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
3724 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
3725 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
3726 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
3727 ADV_DCNT done; /* # calls to request's scsi_done function */
3728 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
3729 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
3730 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
3731 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
3732 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
3733 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
3734 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
3735 ADV_DCNT exe_unknown; /* # unknown returns. */
3736 /* Data Transfer Statistics */
3737 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
3738 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
3739 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
3740 ADV_DCNT sg_elem; /* # scatter-gather elements */
3741 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742};
3743#endif /* ADVANSYS_STATS */
3744
3745/*
3746 * Request queuing structure
3747 */
3748typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003749 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
3750 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
3751 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003753 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
3754 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
3755 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
3756 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
3757 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
3758 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
3759#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760} asc_queue_t;
3761
3762/*
3763 * Adv Library Request Structures
3764 *
3765 * The following two structures are used to process Wide Board requests.
3766 *
3767 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
3768 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
3769 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
3770 * Mid-Level SCSI request structure.
3771 *
3772 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
3773 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
3774 * up to 255 scatter-gather elements may be used per request or
3775 * ADV_SCSI_REQ_Q.
3776 *
3777 * Both structures must be 32 byte aligned.
3778 */
3779typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003780 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
3781 uchar align[32]; /* Sgblock structure padding. */
3782 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783} adv_sgblk_t;
3784
3785typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003786 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
3787 uchar align[32]; /* Request structure padding. */
3788 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
3789 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
3790 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791} adv_req_t;
3792
3793/*
3794 * Structure allocated for each board.
3795 *
3796 * This structure is allocated by scsi_register() at the end
3797 * of the 'Scsi_Host' structure starting at the 'hostdata'
3798 * field. It is guaranteed to be allocated from DMA-able memory.
3799 */
3800typedef struct asc_board {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003801 int id; /* Board Id */
3802 uint flags; /* Board flags */
3803 union {
3804 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
3805 ADV_DVC_VAR adv_dvc_var; /* Wide board */
3806 } dvc_var;
3807 union {
3808 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
3809 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
3810 } dvc_cfg;
3811 ushort asc_n_io_port; /* Number I/O ports. */
3812 asc_queue_t active; /* Active command queue */
3813 asc_queue_t waiting; /* Waiting command queue */
3814 asc_queue_t done; /* Done command queue */
3815 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
3816 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
3817 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
3818 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
3819 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
3820 union {
3821 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
3822 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
3823 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
3824 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
3825 } eep_config;
3826 ulong last_reset; /* Saved last reset time */
3827 spinlock_t lock; /* Board spinlock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003829 /* /proc/scsi/advansys/[0...] */
3830 char *prtbuf; /* /proc print buffer */
3831#endif /* CONFIG_PROC_FS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003833 struct asc_stats asc_stats; /* Board statistics */
3834#endif /* ADVANSYS_STATS */
3835 /*
3836 * The following fields are used only for Narrow Boards.
3837 */
3838 /* The following three structures must be in DMA-able memory. */
3839 ASC_SCSI_REQ_Q scsireqq;
3840 ASC_CAP_INFO cap_info;
3841 ASC_SCSI_INQUIRY inquiry;
3842 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3843 /*
3844 * The following fields are used only for Wide Boards.
3845 */
3846 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3847 ushort ioport; /* I/O Port address. */
3848 ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */
3849 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3850 adv_req_t *adv_reqp; /* Request structures. */
3851 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3852 ushort bios_signature; /* BIOS Signature. */
3853 ushort bios_version; /* BIOS Version. */
3854 ushort bios_codeseg; /* BIOS Code Segment. */
3855 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856} asc_board_t;
3857
3858/*
3859 * PCI configuration structures
3860 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003861typedef struct _PCI_DATA_ {
3862 uchar type;
3863 uchar bus;
3864 uchar slot;
3865 uchar func;
3866 uchar offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867} PCI_DATA;
3868
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003869typedef struct _PCI_DEVICE_ {
3870 ushort vendorID;
3871 ushort deviceID;
3872 ushort slotNumber;
3873 ushort slotFound;
3874 uchar busNumber;
3875 uchar maxBusNumber;
3876 uchar devFunc;
3877 ushort startSlot;
3878 ushort endSlot;
3879 uchar bridge;
3880 uchar type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881} PCI_DEVICE;
3882
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003883typedef struct _PCI_CONFIG_SPACE_ {
3884 ushort vendorID;
3885 ushort deviceID;
3886 ushort command;
3887 ushort status;
3888 uchar revision;
3889 uchar classCode[3];
3890 uchar cacheSize;
3891 uchar latencyTimer;
3892 uchar headerType;
3893 uchar bist;
3894 ADV_PADDR baseAddress[6];
3895 ushort reserved[4];
3896 ADV_PADDR optionRomAddr;
3897 ushort reserved2[4];
3898 uchar irqLine;
3899 uchar irqPin;
3900 uchar minGnt;
3901 uchar maxLatency;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902} PCI_CONFIG_SPACE;
3903
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904/*
3905 * --- Driver Data
3906 */
3907
3908/* Note: All driver global data should be initialized. */
3909
3910/* Number of boards detected in system. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003911static int asc_board_count = 0;
3912static struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913
3914/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003915static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916
3917/*
3918 * Global structures required to issue a command.
3919 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003920static ASC_SCSI_Q asc_scsi_q = { {0} };
3921static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922
3923/* List of supported bus types. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003924static ushort asc_bus[ASC_NUM_BUS] __initdata = {
3925 ASC_IS_ISA,
3926 ASC_IS_VL,
3927 ASC_IS_EISA,
3928 ASC_IS_PCI,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929};
3930
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003931static int asc_iopflag = ASC_FALSE;
3932static int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933
3934#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003935static char *asc_bus_name[ASC_NUM_BUS] = {
3936 "ASC_IS_ISA",
3937 "ASC_IS_VL",
3938 "ASC_IS_EISA",
3939 "ASC_IS_PCI",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940};
3941
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003942static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943#endif /* ADVANSYS_DEBUG */
3944
3945/* Declaration for Asc Library internal data referenced by driver. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003946static PortAddr _asc_def_iop_base[];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947
3948/*
3949 * --- Driver Function Prototypes
3950 *
3951 * advansys.h contains function prototypes for functions global to Linux.
3952 */
3953
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003954static irqreturn_t advansys_interrupt(int, void *);
3955static int advansys_slave_configure(struct scsi_device *);
3956static void asc_scsi_done_list(struct scsi_cmnd *);
3957static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3958static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3959static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3960static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
3961static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
3962static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3963static void adv_async_callback(ADV_DVC_VAR *, uchar);
3964static void asc_enqueue(asc_queue_t *, REQP, int);
3965static REQP asc_dequeue(asc_queue_t *, int);
3966static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3967static int asc_rmqueue(asc_queue_t *, REQP);
3968static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003970static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3971static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3972static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3973static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3974static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3975static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3976static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3977static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3978static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3979static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980#endif /* CONFIG_PROC_FS */
3981
3982/* Declaration for Asc Library internal functions referenced by driver. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003983static int AscFindSignature(PortAddr);
3984static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985
3986/* Statistics function prototypes. */
3987#ifdef ADVANSYS_STATS
3988#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003989static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3990static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991#endif /* CONFIG_PROC_FS */
3992#endif /* ADVANSYS_STATS */
3993
3994/* Debug function prototypes. */
3995#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003996static void asc_prt_scsi_host(struct Scsi_Host *);
3997static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
3998static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
3999static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
4000static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
4001static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
4002static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
4003static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
4004static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
4005static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
4006static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007#endif /* ADVANSYS_DEBUG */
4008
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009#ifdef CONFIG_PROC_FS
4010/*
4011 * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
4012 *
4013 * *buffer: I/O buffer
4014 * **start: if inout == FALSE pointer into buffer where user read should start
4015 * offset: current offset into a /proc/scsi/advansys/[0...] file
4016 * length: length of buffer
4017 * hostno: Scsi_Host host_no
4018 * inout: TRUE - user is writing; FALSE - user is reading
4019 *
4020 * Return the number of bytes read from or written to a
4021 * /proc/scsi/advansys/[0...] file.
4022 *
4023 * Note: This function uses the per board buffer 'prtbuf' which is
4024 * allocated when the board is initialized in advansys_detect(). The
4025 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
4026 * used to write to the buffer. The way asc_proc_copy() is written
4027 * if 'prtbuf' is too small it will not be overwritten. Instead the
4028 * user just won't get all the available statistics.
4029 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004030static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004032 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004034 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004035 char *cp;
4036 int cplen;
4037 int cnt;
4038 int totcnt;
4039 int leftlen;
4040 char *curbuf;
4041 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004043 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044#endif /* ADVANSYS_STATS */
4045
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004046 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004048 /*
4049 * User write not supported.
4050 */
4051 if (inout == TRUE) {
4052 return (-ENOSYS);
4053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004055 /*
4056 * User read of /proc/scsi/advansys/[0...] file.
4057 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058
Matthew Wilcox2a437952007-07-26 11:00:51 -04004059 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004061 /* Copy read data starting at the beginning of the buffer. */
4062 *start = buffer;
4063 curbuf = buffer;
4064 advoffset = 0;
4065 totcnt = 0;
4066 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004068 /*
4069 * Get board configuration information.
4070 *
4071 * advansys_info() returns the board string from its own static buffer.
4072 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04004073 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004074 strcat(cp, "\n");
4075 cplen = strlen(cp);
4076 /* Copy board information. */
4077 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4078 totcnt += cnt;
4079 leftlen -= cnt;
4080 if (leftlen == 0) {
4081 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4082 return totcnt;
4083 }
4084 advoffset += cplen;
4085 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004087 /*
4088 * Display Wide Board BIOS Information.
4089 */
4090 if (ASC_WIDE_BOARD(boardp)) {
4091 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004092 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004093 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4094 cnt =
4095 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
4096 cplen);
4097 totcnt += cnt;
4098 leftlen -= cnt;
4099 if (leftlen == 0) {
4100 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4101 return totcnt;
4102 }
4103 advoffset += cplen;
4104 curbuf += cnt;
4105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004107 /*
4108 * Display driver information for each device attached to the board.
4109 */
4110 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004111 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004112 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4113 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4114 totcnt += cnt;
4115 leftlen -= cnt;
4116 if (leftlen == 0) {
4117 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4118 return totcnt;
4119 }
4120 advoffset += cplen;
4121 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004123 /*
4124 * Display EEPROM configuration for the board.
4125 */
4126 cp = boardp->prtbuf;
4127 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004128 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004129 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004130 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004131 }
4132 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4133 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4134 totcnt += cnt;
4135 leftlen -= cnt;
4136 if (leftlen == 0) {
4137 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4138 return totcnt;
4139 }
4140 advoffset += cplen;
4141 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004143 /*
4144 * Display driver configuration and information for the board.
4145 */
4146 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004147 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004148 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4149 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4150 totcnt += cnt;
4151 leftlen -= cnt;
4152 if (leftlen == 0) {
4153 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4154 return totcnt;
4155 }
4156 advoffset += cplen;
4157 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158
4159#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004160 /*
4161 * Display driver statistics for the board.
4162 */
4163 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004164 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004165 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4166 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4167 totcnt += cnt;
4168 leftlen -= cnt;
4169 if (leftlen == 0) {
4170 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4171 return totcnt;
4172 }
4173 advoffset += cplen;
4174 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004176 /*
4177 * Display driver statistics for each target.
4178 */
4179 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
4180 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004181 cplen = asc_prt_target_stats(shost, tgt_id, cp,
4182 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004183 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4184 cnt =
4185 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
4186 cplen);
4187 totcnt += cnt;
4188 leftlen -= cnt;
4189 if (leftlen == 0) {
4190 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4191 return totcnt;
4192 }
4193 advoffset += cplen;
4194 curbuf += cnt;
4195 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196#endif /* ADVANSYS_STATS */
4197
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004198 /*
4199 * Display Asc Library dynamic configuration information
4200 * for the board.
4201 */
4202 cp = boardp->prtbuf;
4203 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004204 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004205 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004206 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004207 }
4208 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4209 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4210 totcnt += cnt;
4211 leftlen -= cnt;
4212 if (leftlen == 0) {
4213 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4214 return totcnt;
4215 }
4216 advoffset += cplen;
4217 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004219 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004221 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222}
4223#endif /* CONFIG_PROC_FS */
4224
4225/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 * advansys_info()
4227 *
4228 * Return suitable for printing on the console with the argument
4229 * adapter's configuration information.
4230 *
4231 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
4232 * otherwise the static 'info' array will be overrun.
4233 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004234static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004236 static char info[ASC_INFO_SIZE];
4237 asc_board_t *boardp;
4238 ASC_DVC_VAR *asc_dvc_varp;
4239 ADV_DVC_VAR *adv_dvc_varp;
4240 char *busname;
4241 int iolen;
4242 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004244 boardp = ASC_BOARDP(shost);
4245 if (ASC_NARROW_BOARD(boardp)) {
4246 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
4247 ASC_DBG(1, "advansys_info: begin\n");
4248 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
4249 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
4250 ASC_IS_ISAPNP) {
4251 busname = "ISA PnP";
4252 } else {
4253 busname = "ISA";
4254 }
4255 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4256 sprintf(info,
4257 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
4258 ASC_VERSION, busname,
4259 (ulong)shost->io_port,
4260 (ulong)shost->io_port + boardp->asc_n_io_port -
4261 1, shost->irq, shost->dma_channel);
4262 } else {
4263 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
4264 busname = "VL";
4265 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
4266 busname = "EISA";
4267 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
4268 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
4269 == ASC_IS_PCI_ULTRA) {
4270 busname = "PCI Ultra";
4271 } else {
4272 busname = "PCI";
4273 }
4274 } else {
4275 busname = "?";
4276 ASC_PRINT2
4277 ("advansys_info: board %d: unknown bus type %d\n",
4278 boardp->id, asc_dvc_varp->bus_type);
4279 }
4280 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4281 sprintf(info,
4282 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
4283 ASC_VERSION, busname,
4284 (ulong)shost->io_port,
4285 (ulong)shost->io_port + boardp->asc_n_io_port -
4286 1, shost->irq);
4287 }
4288 } else {
4289 /*
4290 * Wide Adapter Information
4291 *
4292 * Memory-mapped I/O is used instead of I/O space to access
4293 * the adapter, but display the I/O Port range. The Memory
4294 * I/O address is displayed through the driver /proc file.
4295 */
4296 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4297 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4298 iolen = ADV_3550_IOLEN;
4299 widename = "Ultra-Wide";
4300 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4301 iolen = ADV_38C0800_IOLEN;
4302 widename = "Ultra2-Wide";
4303 } else {
4304 iolen = ADV_38C1600_IOLEN;
4305 widename = "Ultra3-Wide";
4306 }
4307 sprintf(info,
4308 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
4309 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
4310 (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
4311 }
4312 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
4313 ASC_DBG(1, "advansys_info: end\n");
4314 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315}
4316
4317/*
4318 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
4319 *
4320 * This function always returns 0. Command return status is saved
4321 * in the 'scp' result field.
4322 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004323static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004324advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004326 struct Scsi_Host *shost;
4327 asc_board_t *boardp;
4328 ulong flags;
4329 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004331 shost = scp->device->host;
4332 boardp = ASC_BOARDP(shost);
4333 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004335 /* host_lock taken by mid-level prior to call but need to protect */
4336 /* against own ISR */
4337 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004339 /*
4340 * Block new commands while handling a reset or abort request.
4341 */
4342 if (boardp->flags & ASC_HOST_IN_RESET) {
4343 ASC_DBG1(1,
4344 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4345 (ulong)scp);
4346 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004348 /*
4349 * Add blocked requests to the board's 'done' queue. The queued
4350 * requests will be completed at the end of the abort or reset
4351 * handling.
4352 */
4353 asc_enqueue(&boardp->done, scp, ASC_BACK);
4354 spin_unlock_irqrestore(&boardp->lock, flags);
4355 return 0;
4356 }
4357
4358 /*
4359 * Attempt to execute any waiting commands for the board.
4360 */
4361 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4362 ASC_DBG(1,
4363 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4364 asc_execute_queue(&boardp->waiting);
4365 }
4366
4367 /*
4368 * Save the function pointer to Linux mid-level 'done' function
4369 * and attempt to execute the command.
4370 *
4371 * If ASC_NOERROR is returned the request has been added to the
4372 * board's 'active' queue and will be completed by the interrupt
4373 * handler.
4374 *
4375 * If ASC_BUSY is returned add the request to the board's per
4376 * target waiting list. This is the first time the request has
4377 * been tried. Add it to the back of the waiting list. It will be
4378 * retried later.
4379 *
4380 * If an error occurred, the request will have been placed on the
4381 * board's 'done' queue and must be completed before returning.
4382 */
4383 scp->scsi_done = done;
4384 switch (asc_execute_scsi_cmnd(scp)) {
4385 case ASC_NOERROR:
4386 break;
4387 case ASC_BUSY:
4388 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4389 break;
4390 case ASC_ERROR:
4391 default:
4392 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4393 /* Interrupts could be enabled here. */
4394 asc_scsi_done_list(done_scp);
4395 break;
4396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004399 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400}
4401
4402/*
4403 * advansys_reset()
4404 *
4405 * Reset the bus associated with the command 'scp'.
4406 *
4407 * This function runs its own thread. Interrupts must be blocked but
4408 * sleeping is allowed and no locking other than for host structures is
4409 * required. Returns SUCCESS or FAILED.
4410 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004411static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004413 struct Scsi_Host *shost;
4414 asc_board_t *boardp;
4415 ASC_DVC_VAR *asc_dvc_varp;
4416 ADV_DVC_VAR *adv_dvc_varp;
4417 ulong flags;
4418 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4419 struct scsi_cmnd *tscp, *new_last_scp;
4420 int status;
4421 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004423 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424
4425#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004426 if (scp->device->host != NULL) {
4427 ASC_STATS(scp->device->host, reset);
4428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429#endif /* ADVANSYS_STATS */
4430
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004431 if ((shost = scp->device->host) == NULL) {
4432 scp->result = HOST_BYTE(DID_ERROR);
4433 return FAILED;
4434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004436 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004438 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4439 boardp->id);
4440 /*
4441 * Check for re-entrancy.
4442 */
4443 spin_lock_irqsave(&boardp->lock, flags);
4444 if (boardp->flags & ASC_HOST_IN_RESET) {
4445 spin_unlock_irqrestore(&boardp->lock, flags);
4446 return FAILED;
4447 }
4448 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004451 if (ASC_NARROW_BOARD(boardp)) {
4452 /*
4453 * Narrow Board
4454 */
4455 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004457 /*
4458 * Reset the chip and SCSI bus.
4459 */
4460 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4461 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004463 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4464 if (asc_dvc_varp->err_code) {
4465 ASC_PRINT2
4466 ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
4467 boardp->id, asc_dvc_varp->err_code);
4468 ret = FAILED;
4469 } else if (status) {
4470 ASC_PRINT2
4471 ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
4472 boardp->id, status);
4473 } else {
4474 ASC_PRINT1
4475 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4476 boardp->id);
4477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004479 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4480 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004482 } else {
4483 /*
4484 * Wide Board
4485 *
4486 * If the suggest reset bus flags are set, then reset the bus.
4487 * Otherwise only reset the device.
4488 */
4489 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004491 /*
4492 * Reset the target's SCSI bus.
4493 */
4494 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4495 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4496 case ASC_TRUE:
4497 ASC_PRINT1
4498 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4499 boardp->id);
4500 break;
4501 case ASC_FALSE:
4502 default:
4503 ASC_PRINT1
4504 ("advansys_reset: board %d: SCSI bus reset error.\n",
4505 boardp->id);
4506 ret = FAILED;
4507 break;
4508 }
4509 spin_lock_irqsave(&boardp->lock, flags);
4510 (void)AdvISR(adv_dvc_varp);
4511 }
4512 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004514 /*
4515 * Dequeue all board 'done' requests. A pointer to the last request
4516 * is returned in 'last_scp'.
4517 */
4518 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004520 /*
4521 * Dequeue all board 'active' requests for all devices and set
4522 * the request status to DID_RESET. A pointer to the last request
4523 * is returned in 'last_scp'.
4524 */
4525 if (done_scp == NULL) {
4526 done_scp =
4527 asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
4528 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4529 tscp->result = HOST_BYTE(DID_RESET);
4530 }
4531 } else {
4532 /* Append to 'done_scp' at the end with 'last_scp'. */
4533 ASC_ASSERT(last_scp != NULL);
4534 last_scp->host_scribble =
4535 (unsigned char *)asc_dequeue_list(&boardp->active,
4536 &new_last_scp,
4537 ASC_TID_ALL);
4538 if (new_last_scp != NULL) {
4539 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4540 for (tscp = REQPNEXT(last_scp); tscp;
4541 tscp = REQPNEXT(tscp)) {
4542 tscp->result = HOST_BYTE(DID_RESET);
4543 }
4544 last_scp = new_last_scp;
4545 }
4546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004548 /*
4549 * Dequeue all 'waiting' requests and set the request status
4550 * to DID_RESET.
4551 */
4552 if (done_scp == NULL) {
4553 done_scp =
4554 asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
4555 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4556 tscp->result = HOST_BYTE(DID_RESET);
4557 }
4558 } else {
4559 /* Append to 'done_scp' at the end with 'last_scp'. */
4560 ASC_ASSERT(last_scp != NULL);
4561 last_scp->host_scribble =
4562 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4563 &new_last_scp,
4564 ASC_TID_ALL);
4565 if (new_last_scp != NULL) {
4566 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4567 for (tscp = REQPNEXT(last_scp); tscp;
4568 tscp = REQPNEXT(tscp)) {
4569 tscp->result = HOST_BYTE(DID_RESET);
4570 }
4571 last_scp = new_last_scp;
4572 }
4573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004575 /* Save the time of the most recently completed reset. */
4576 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004578 /* Clear reset flag. */
4579 boardp->flags &= ~ASC_HOST_IN_RESET;
4580 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004582 /*
4583 * Complete all the 'done_scp' requests.
4584 */
4585 if (done_scp != NULL) {
4586 asc_scsi_done_list(done_scp);
4587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004589 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004591 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592}
4593
4594/*
4595 * advansys_biosparam()
4596 *
4597 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4598 * support is enabled for a drive.
4599 *
4600 * ip (information pointer) is an int array with the following definition:
4601 * ip[0]: heads
4602 * ip[1]: sectors
4603 * ip[2]: cylinders
4604 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004605static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004607 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004609 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004611 ASC_DBG(1, "advansys_biosparam: begin\n");
4612 ASC_STATS(sdev->host, biosparam);
4613 boardp = ASC_BOARDP(sdev->host);
4614 if (ASC_NARROW_BOARD(boardp)) {
4615 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4616 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4617 ip[0] = 255;
4618 ip[1] = 63;
4619 } else {
4620 ip[0] = 64;
4621 ip[1] = 32;
4622 }
4623 } else {
4624 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4625 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4626 ip[0] = 255;
4627 ip[1] = 63;
4628 } else {
4629 ip[0] = 64;
4630 ip[1] = 32;
4631 }
4632 }
4633 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4634 ASC_DBG(1, "advansys_biosparam: end\n");
4635 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636}
4637
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004638static int __init advansys_detect(struct scsi_host_template *tpnt);
4639static int advansys_release(struct Scsi_Host *shp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640
4641static struct scsi_host_template driver_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004642 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004644 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004646 .name = "advansys",
4647 .detect = advansys_detect,
4648 .release = advansys_release,
4649 .info = advansys_info,
4650 .queuecommand = advansys_queuecommand,
4651 .eh_bus_reset_handler = advansys_reset,
4652 .bios_param = advansys_biosparam,
4653 .slave_configure = advansys_slave_configure,
4654 /*
4655 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
4656 * must be set. The flag will be cleared in advansys_detect for non-ISA
4657 * adapters. Refer to the comment in scsi_module.c for more information.
4658 */
4659 .unchecked_isa_dma = 1,
4660 /*
4661 * All adapters controlled by this driver are capable of large
4662 * scatter-gather lists. According to the mid-level SCSI documentation
4663 * this obviates any performance gain provided by setting
4664 * 'use_clustering'. But empirically while CPU utilization is increased
4665 * by enabling clustering, I/O throughput increases as well.
4666 */
4667 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004670#include "scsi_module.c"
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671
4672/*
4673 * --- Miscellaneous Driver Functions
4674 */
4675
4676/*
4677 * First-level interrupt handler.
4678 *
4679 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4680 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4681 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4682 * to the AdvanSys driver which is for a device sharing an interrupt with
4683 * an AdvanSys adapter.
4684 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004685static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004687 ulong flags;
4688 int i;
4689 asc_board_t *boardp;
4690 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4691 struct scsi_cmnd *new_last_scp;
4692 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004694 ASC_DBG(1, "advansys_interrupt: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004696 /*
4697 * Check for interrupts on all boards.
4698 * AscISR() will call asc_isr_callback().
4699 */
4700 for (i = 0; i < asc_board_count; i++) {
4701 shost = asc_host[i];
4702 boardp = ASC_BOARDP(shost);
4703 ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
4704 i, (ulong)boardp);
4705 spin_lock_irqsave(&boardp->lock, flags);
4706 if (ASC_NARROW_BOARD(boardp)) {
4707 /*
4708 * Narrow Board
4709 */
4710 if (AscIsIntPending(shost->io_port)) {
4711 ASC_STATS(shost, interrupt);
4712 ASC_DBG(1,
4713 "advansys_interrupt: before AscISR()\n");
4714 AscISR(&boardp->dvc_var.asc_dvc_var);
4715 }
4716 } else {
4717 /*
4718 * Wide Board
4719 */
4720 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4721 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4722 ASC_STATS(shost, interrupt);
4723 }
4724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004726 /*
4727 * Start waiting requests and create a list of completed requests.
4728 *
4729 * If a reset request is being performed for the board, the reset
4730 * handler will complete pending requests after it has completed.
4731 */
4732 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4733 ASC_DBG2(1,
4734 "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n",
4735 (ulong)done_scp, (ulong)last_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004737 /* Start any waiting commands for the board. */
4738 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4739 ASC_DBG(1,
4740 "advansys_interrupt: before asc_execute_queue()\n");
4741 asc_execute_queue(&boardp->waiting);
4742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004744 /*
4745 * Add to the list of requests that must be completed.
4746 *
4747 * 'done_scp' will always be NULL on the first iteration
4748 * of this loop. 'last_scp' is set at the same time as
4749 * 'done_scp'.
4750 */
4751 if (done_scp == NULL) {
4752 done_scp =
4753 asc_dequeue_list(&boardp->done, &last_scp,
4754 ASC_TID_ALL);
4755 } else {
4756 ASC_ASSERT(last_scp != NULL);
4757 last_scp->host_scribble =
4758 (unsigned char *)asc_dequeue_list(&boardp->
4759 done,
4760 &new_last_scp,
4761 ASC_TID_ALL);
4762 if (new_last_scp != NULL) {
4763 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4764 last_scp = new_last_scp;
4765 }
4766 }
4767 }
4768 spin_unlock_irqrestore(&boardp->lock, flags);
4769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004771 /*
4772 * If interrupts were enabled on entry, then they
4773 * are now enabled here.
4774 *
4775 * Complete all requests on the done list.
4776 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004778 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004780 ASC_DBG(1, "advansys_interrupt: end\n");
4781 return IRQ_HANDLED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782}
4783
4784/*
4785 * Set the number of commands to queue per device for the
4786 * specified host adapter.
4787 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004788static int advansys_slave_configure(struct scsi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004790 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004792 boardp = ASC_BOARDP(device->host);
4793 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
4794 /*
4795 * Save a pointer to the device and set its initial/maximum
4796 * queue depth. Only save the pointer for a lun0 dev though.
4797 */
4798 if (device->lun == 0)
4799 boardp->device[device->id] = device;
4800 if (device->tagged_supported) {
4801 if (ASC_NARROW_BOARD(boardp)) {
4802 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4803 boardp->dvc_var.asc_dvc_var.
4804 max_dvc_qng[device->id]);
4805 } else {
4806 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4807 boardp->dvc_var.adv_dvc_var.
4808 max_dvc_qng);
4809 }
4810 } else {
4811 scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
4812 }
4813 ASC_DBG4(1,
4814 "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
4815 (ulong)device, (ulong)boardp, device->id, device->queue_depth);
4816 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817}
4818
4819/*
4820 * Complete all requests on the singly linked list pointed
4821 * to by 'scp'.
4822 *
4823 * Interrupts can be enabled on entry.
4824 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004825static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004827 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004829 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4830 while (scp != NULL) {
4831 asc_board_t *boardp;
4832 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004834 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4835 tscp = REQPNEXT(scp);
4836 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004838 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004840 if (ASC_NARROW_BOARD(boardp))
4841 dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
4842 else
4843 dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004845 if (scp->use_sg)
4846 dma_unmap_sg(dev,
4847 (struct scatterlist *)scp->request_buffer,
4848 scp->use_sg, scp->sc_data_direction);
4849 else if (scp->request_bufflen)
4850 dma_unmap_single(dev, scp->SCp.dma_handle,
4851 scp->request_bufflen,
4852 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004854 ASC_STATS(scp->device->host, done);
4855 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004857 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004859 scp = tscp;
4860 }
4861 ASC_DBG(2, "asc_scsi_done_list: done\n");
4862 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863}
4864
4865/*
4866 * Execute a single 'Scsi_Cmnd'.
4867 *
4868 * The function 'done' is called when the request has been completed.
4869 *
4870 * Scsi_Cmnd:
4871 *
4872 * host - board controlling device
4873 * device - device to send command
4874 * target - target of device
4875 * lun - lun of device
4876 * cmd_len - length of SCSI CDB
4877 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4878 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4879 *
4880 * if (use_sg == 0) {
4881 * request_buffer - buffer address for request
4882 * request_bufflen - length of request buffer
4883 * } else {
4884 * request_buffer - pointer to scatterlist structure
4885 * }
4886 *
4887 * sense_buffer - sense command buffer
4888 *
4889 * result (4 bytes of an int):
4890 * Byte Meaning
4891 * 0 SCSI Status Byte Code
4892 * 1 SCSI One Byte Message Code
4893 * 2 Host Error Code
4894 * 3 Mid-Level Error Code
4895 *
4896 * host driver fields:
4897 * SCp - Scsi_Pointer used for command processing status
4898 * scsi_done - used to save caller's done function
4899 * host_scribble - used for pointer to another struct scsi_cmnd
4900 *
4901 * If this function returns ASC_NOERROR the request has been enqueued
4902 * on the board's 'active' queue and will be completed from the
4903 * interrupt handler.
4904 *
4905 * If this function returns ASC_NOERROR the request has been enqueued
4906 * on the board's 'done' queue and must be completed by the caller.
4907 *
4908 * If ASC_BUSY is returned the request will be enqueued by the
4909 * caller on the target's waiting queue and re-tried later.
4910 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004911static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004913 asc_board_t *boardp;
4914 ASC_DVC_VAR *asc_dvc_varp;
4915 ADV_DVC_VAR *adv_dvc_varp;
4916 ADV_SCSI_REQ_Q *adv_scsiqp;
4917 struct scsi_device *device;
4918 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004920 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4921 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004923 boardp = ASC_BOARDP(scp->device->host);
4924 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004926 if (ASC_NARROW_BOARD(boardp)) {
4927 /*
4928 * Build and execute Narrow Board request.
4929 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004931 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004933 /*
4934 * Build Asc Library request structure using the
4935 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4936 *
4937 * If an error is returned, then the request has been
4938 * queued on the board done queue. It will be completed
4939 * by the caller.
4940 *
4941 * asc_build_req() can not return ASC_BUSY.
4942 */
4943 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4944 ASC_STATS(scp->device->host, build_error);
4945 return ASC_ERROR;
4946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004948 /*
4949 * Execute the command. If there is no error, add the command
4950 * to the active queue.
4951 */
4952 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4953 case ASC_NOERROR:
4954 ASC_STATS(scp->device->host, exe_noerror);
4955 /*
4956 * Increment monotonically increasing per device successful
4957 * request counter. Wrapping doesn't matter.
4958 */
4959 boardp->reqcnt[scp->device->id]++;
4960 asc_enqueue(&boardp->active, scp, ASC_BACK);
4961 ASC_DBG(1,
4962 "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
4963 break;
4964 case ASC_BUSY:
4965 /*
4966 * Caller will enqueue request on the target's waiting queue
4967 * and retry later.
4968 */
4969 ASC_STATS(scp->device->host, exe_busy);
4970 break;
4971 case ASC_ERROR:
4972 ASC_PRINT2
4973 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4974 boardp->id, asc_dvc_varp->err_code);
4975 ASC_STATS(scp->device->host, exe_error);
4976 scp->result = HOST_BYTE(DID_ERROR);
4977 asc_enqueue(&boardp->done, scp, ASC_BACK);
4978 break;
4979 default:
4980 ASC_PRINT2
4981 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
4982 boardp->id, asc_dvc_varp->err_code);
4983 ASC_STATS(scp->device->host, exe_unknown);
4984 scp->result = HOST_BYTE(DID_ERROR);
4985 asc_enqueue(&boardp->done, scp, ASC_BACK);
4986 break;
4987 }
4988 } else {
4989 /*
4990 * Build and execute Wide Board request.
4991 */
4992 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004994 /*
4995 * Build and get a pointer to an Adv Library request structure.
4996 *
4997 * If the request is successfully built then send it below,
4998 * otherwise return with an error.
4999 */
5000 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
5001 case ASC_NOERROR:
5002 ASC_DBG(3,
5003 "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
5004 break;
5005 case ASC_BUSY:
5006 ASC_DBG(1,
5007 "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
5008 /*
5009 * If busy is returned the request has not been enqueued.
5010 * It will be enqueued by the caller on the target's waiting
5011 * queue and retried later.
5012 *
5013 * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
5014 * count wide board busy conditions. They are updated in
5015 * adv_build_req and adv_get_sglist, respectively.
5016 */
5017 return ASC_BUSY;
5018 case ASC_ERROR:
5019 /*
5020 * If an error is returned, then the request has been
5021 * queued on the board done queue. It will be completed
5022 * by the caller.
5023 */
5024 default:
5025 ASC_DBG(1,
5026 "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
5027 ASC_STATS(scp->device->host, build_error);
5028 return ASC_ERROR;
5029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005031 /*
5032 * Execute the command. If there is no error, add the command
5033 * to the active queue.
5034 */
5035 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
5036 case ASC_NOERROR:
5037 ASC_STATS(scp->device->host, exe_noerror);
5038 /*
5039 * Increment monotonically increasing per device successful
5040 * request counter. Wrapping doesn't matter.
5041 */
5042 boardp->reqcnt[scp->device->id]++;
5043 asc_enqueue(&boardp->active, scp, ASC_BACK);
5044 ASC_DBG(1,
5045 "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
5046 break;
5047 case ASC_BUSY:
5048 /*
5049 * Caller will enqueue request on the target's waiting queue
5050 * and retry later.
5051 */
5052 ASC_STATS(scp->device->host, exe_busy);
5053 break;
5054 case ASC_ERROR:
5055 ASC_PRINT2
5056 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
5057 boardp->id, adv_dvc_varp->err_code);
5058 ASC_STATS(scp->device->host, exe_error);
5059 scp->result = HOST_BYTE(DID_ERROR);
5060 asc_enqueue(&boardp->done, scp, ASC_BACK);
5061 break;
5062 default:
5063 ASC_PRINT2
5064 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
5065 boardp->id, adv_dvc_varp->err_code);
5066 ASC_STATS(scp->device->host, exe_unknown);
5067 scp->result = HOST_BYTE(DID_ERROR);
5068 asc_enqueue(&boardp->done, scp, ASC_BACK);
5069 break;
5070 }
5071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005073 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
5074 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075}
5076
5077/*
5078 * Build a request structure for the Asc Library (Narrow Board).
5079 *
5080 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
5081 * used to build the request.
5082 *
5083 * If an error occurs, then queue the request on the board done
5084 * queue and return ASC_ERROR.
5085 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005086static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005088 struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005090 /*
5091 * Mutually exclusive access is required to 'asc_scsi_q' and
5092 * 'asc_sg_head' until after the request is started.
5093 */
5094 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005096 /*
5097 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
5098 */
5099 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005101 /*
5102 * Build the ASC_SCSI_Q request.
5103 *
5104 * For narrow boards a CDB length maximum of 12 bytes
5105 * is supported.
5106 */
5107 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
5108 ASC_PRINT3
5109 ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n",
5110 boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
5111 scp->result = HOST_BYTE(DID_ERROR);
5112 asc_enqueue(&boardp->done, scp, ASC_BACK);
5113 return ASC_ERROR;
5114 }
5115 asc_scsi_q.cdbptr = &scp->cmnd[0];
5116 asc_scsi_q.q2.cdb_len = scp->cmd_len;
5117 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
5118 asc_scsi_q.q1.target_lun = scp->device->lun;
5119 asc_scsi_q.q2.target_ix =
5120 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
5121 asc_scsi_q.q1.sense_addr =
5122 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5123 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005125 /*
5126 * If there are any outstanding requests for the current target,
5127 * then every 255th request send an ORDERED request. This heuristic
5128 * tries to retain the benefit of request sorting while preventing
5129 * request starvation. 255 is the max number of tags or pending commands
5130 * a device may have outstanding.
5131 *
5132 * The request count is incremented below for every successfully
5133 * started request.
5134 *
5135 */
5136 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
5137 (boardp->reqcnt[scp->device->id] % 255) == 0) {
5138 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
5139 } else {
5140 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
5141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005143 /*
5144 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
5145 * buffer command.
5146 */
5147 if (scp->use_sg == 0) {
5148 /*
5149 * CDB request of single contiguous buffer.
5150 */
5151 ASC_STATS(scp->device->host, cont_cnt);
5152 scp->SCp.dma_handle = scp->request_bufflen ?
5153 dma_map_single(dev, scp->request_buffer,
5154 scp->request_bufflen,
5155 scp->sc_data_direction) : 0;
5156 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
5157 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
5158 ASC_STATS_ADD(scp->device->host, cont_xfer,
5159 ASC_CEILING(scp->request_bufflen, 512));
5160 asc_scsi_q.q1.sg_queue_cnt = 0;
5161 asc_scsi_q.sg_head = NULL;
5162 } else {
5163 /*
5164 * CDB scatter-gather request list.
5165 */
5166 int sgcnt;
5167 int use_sg;
5168 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005170 slp = (struct scatterlist *)scp->request_buffer;
5171 use_sg =
5172 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005174 if (use_sg > scp->device->host->sg_tablesize) {
5175 ASC_PRINT3
5176 ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
5177 boardp->id, use_sg,
5178 scp->device->host->sg_tablesize);
5179 dma_unmap_sg(dev, slp, scp->use_sg,
5180 scp->sc_data_direction);
5181 scp->result = HOST_BYTE(DID_ERROR);
5182 asc_enqueue(&boardp->done, scp, ASC_BACK);
5183 return ASC_ERROR;
5184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005186 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005188 /*
5189 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
5190 * structure to point to it.
5191 */
5192 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005194 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5195 asc_scsi_q.sg_head = &asc_sg_head;
5196 asc_scsi_q.q1.data_cnt = 0;
5197 asc_scsi_q.q1.data_addr = 0;
5198 /* This is a byte value, otherwise it would need to be swapped. */
5199 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5200 ASC_STATS_ADD(scp->device->host, sg_elem,
5201 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005203 /*
5204 * Convert scatter-gather list into ASC_SG_HEAD list.
5205 */
5206 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5207 asc_sg_head.sg_list[sgcnt].addr =
5208 cpu_to_le32(sg_dma_address(slp));
5209 asc_sg_head.sg_list[sgcnt].bytes =
5210 cpu_to_le32(sg_dma_len(slp));
5211 ASC_STATS_ADD(scp->device->host, sg_xfer,
5212 ASC_CEILING(sg_dma_len(slp), 512));
5213 }
5214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005216 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5217 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005219 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220}
5221
5222/*
5223 * Build a request structure for the Adv Library (Wide Board).
5224 *
5225 * If an adv_req_t can not be allocated to issue the request,
5226 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5227 *
5228 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5229 * microcode for DMA addresses or math operations are byte swapped
5230 * to little-endian order.
5231 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005232static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005234 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005236 adv_req_t *reqp;
5237 ADV_SCSI_REQ_Q *scsiqp;
5238 int i;
5239 int ret;
5240 struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005242 /*
5243 * Allocate an adv_req_t structure from the board to execute
5244 * the command.
5245 */
5246 if (boardp->adv_reqp == NULL) {
5247 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5248 ASC_STATS(scp->device->host, adv_build_noreq);
5249 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005251 reqp = boardp->adv_reqp;
5252 boardp->adv_reqp = reqp->next_reqp;
5253 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005256 /*
5257 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5258 */
5259 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005261 /*
5262 * Initialize the structure.
5263 */
5264 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005266 /*
5267 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5268 */
5269 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005271 /*
5272 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5273 */
5274 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005276 /*
5277 * Build the ADV_SCSI_REQ_Q request.
5278 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005280 /*
5281 * Set CDB length and copy it to the request structure.
5282 * For wide boards a CDB length maximum of 16 bytes
5283 * is supported.
5284 */
5285 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5286 ASC_PRINT3
5287 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5288 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5289 scp->result = HOST_BYTE(DID_ERROR);
5290 asc_enqueue(&boardp->done, scp, ASC_BACK);
5291 return ASC_ERROR;
5292 }
5293 scsiqp->cdb_len = scp->cmd_len;
5294 /* Copy first 12 CDB bytes to cdb[]. */
5295 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5296 scsiqp->cdb[i] = scp->cmnd[i];
5297 }
5298 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5299 for (; i < scp->cmd_len; i++) {
5300 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5301 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005303 scsiqp->target_id = scp->device->id;
5304 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005306 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5307 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005309 /*
5310 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5311 * buffer command.
5312 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005314 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5315 scsiqp->vdata_addr = scp->request_buffer;
5316 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5317
5318 if (scp->use_sg == 0) {
5319 /*
5320 * CDB request of single contiguous buffer.
5321 */
5322 reqp->sgblkp = NULL;
5323 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5324 if (scp->request_bufflen) {
5325 scsiqp->vdata_addr = scp->request_buffer;
5326 scp->SCp.dma_handle =
5327 dma_map_single(dev, scp->request_buffer,
5328 scp->request_bufflen,
5329 scp->sc_data_direction);
5330 } else {
5331 scsiqp->vdata_addr = NULL;
5332 scp->SCp.dma_handle = 0;
5333 }
5334 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5335 scsiqp->sg_list_ptr = NULL;
5336 scsiqp->sg_real_addr = 0;
5337 ASC_STATS(scp->device->host, cont_cnt);
5338 ASC_STATS_ADD(scp->device->host, cont_xfer,
5339 ASC_CEILING(scp->request_bufflen, 512));
5340 } else {
5341 /*
5342 * CDB scatter-gather request list.
5343 */
5344 struct scatterlist *slp;
5345 int use_sg;
5346
5347 slp = (struct scatterlist *)scp->request_buffer;
5348 use_sg =
5349 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
5350
5351 if (use_sg > ADV_MAX_SG_LIST) {
5352 ASC_PRINT3
5353 ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
5354 boardp->id, use_sg,
5355 scp->device->host->sg_tablesize);
5356 dma_unmap_sg(dev, slp, scp->use_sg,
5357 scp->sc_data_direction);
5358 scp->result = HOST_BYTE(DID_ERROR);
5359 asc_enqueue(&boardp->done, scp, ASC_BACK);
5360
5361 /*
5362 * Free the 'adv_req_t' structure by adding it back to the
5363 * board free list.
5364 */
5365 reqp->next_reqp = boardp->adv_reqp;
5366 boardp->adv_reqp = reqp;
5367
5368 return ASC_ERROR;
5369 }
5370
5371 if ((ret =
5372 adv_get_sglist(boardp, reqp, scp,
5373 use_sg)) != ADV_SUCCESS) {
5374 /*
5375 * Free the adv_req_t structure by adding it back to the
5376 * board free list.
5377 */
5378 reqp->next_reqp = boardp->adv_reqp;
5379 boardp->adv_reqp = reqp;
5380
5381 return ret;
5382 }
5383
5384 ASC_STATS(scp->device->host, sg_cnt);
5385 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5386 }
5387
5388 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5389 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5390
5391 *adv_scsiqpp = scsiqp;
5392
5393 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394}
5395
5396/*
5397 * Build scatter-gather list for Adv Library (Wide Board).
5398 *
5399 * Additional ADV_SG_BLOCK structures will need to be allocated
5400 * if the total number of scatter-gather elements exceeds
5401 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5402 * assumed to be physically contiguous.
5403 *
5404 * Return:
5405 * ADV_SUCCESS(1) - SG List successfully created
5406 * ADV_ERROR(-1) - SG List creation failed
5407 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005408static int
5409adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5410 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005412 adv_sgblk_t *sgblkp;
5413 ADV_SCSI_REQ_Q *scsiqp;
5414 struct scatterlist *slp;
5415 int sg_elem_cnt;
5416 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5417 ADV_PADDR sg_block_paddr;
5418 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005420 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5421 slp = (struct scatterlist *)scp->request_buffer;
5422 sg_elem_cnt = use_sg;
5423 prev_sg_block = NULL;
5424 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005426 do {
5427 /*
5428 * Allocate a 'adv_sgblk_t' structure from the board free
5429 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5430 * (15) scatter-gather elements.
5431 */
5432 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5433 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5434 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005436 /*
5437 * Allocation failed. Free 'adv_sgblk_t' structures already
5438 * allocated for the request.
5439 */
5440 while ((sgblkp = reqp->sgblkp) != NULL) {
5441 /* Remove 'sgblkp' from the request list. */
5442 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005444 /* Add 'sgblkp' to the board free list. */
5445 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5446 boardp->adv_sgblkp = sgblkp;
5447 }
5448 return ASC_BUSY;
5449 } else {
5450 /* Complete 'adv_sgblk_t' board allocation. */
5451 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5452 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005454 /*
5455 * Get 8 byte aligned virtual and physical addresses for
5456 * the allocated ADV_SG_BLOCK structure.
5457 */
5458 sg_block =
5459 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5460 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005462 /*
5463 * Check if this is the first 'adv_sgblk_t' for the request.
5464 */
5465 if (reqp->sgblkp == NULL) {
5466 /* Request's first scatter-gather block. */
5467 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005469 /*
5470 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5471 * address pointers.
5472 */
5473 scsiqp->sg_list_ptr = sg_block;
5474 scsiqp->sg_real_addr =
5475 cpu_to_le32(sg_block_paddr);
5476 } else {
5477 /* Request's second or later scatter-gather block. */
5478 sgblkp->next_sgblkp = reqp->sgblkp;
5479 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005481 /*
5482 * Point the previous ADV_SG_BLOCK structure to
5483 * the newly allocated ADV_SG_BLOCK structure.
5484 */
5485 ASC_ASSERT(prev_sg_block != NULL);
5486 prev_sg_block->sg_ptr =
5487 cpu_to_le32(sg_block_paddr);
5488 }
5489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005491 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5492 sg_block->sg_list[i].sg_addr =
5493 cpu_to_le32(sg_dma_address(slp));
5494 sg_block->sg_list[i].sg_count =
5495 cpu_to_le32(sg_dma_len(slp));
5496 ASC_STATS_ADD(scp->device->host, sg_xfer,
5497 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005499 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5500 sg_block->sg_cnt = i + 1;
5501 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5502 return ADV_SUCCESS;
5503 }
5504 slp++;
5505 }
5506 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5507 prev_sg_block = sg_block;
5508 }
5509 while (1);
5510 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511}
5512
5513/*
5514 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5515 *
5516 * Interrupt callback function for the Narrow SCSI Asc Library.
5517 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005518static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005520 asc_board_t *boardp;
5521 struct scsi_cmnd *scp;
5522 struct Scsi_Host *shost;
5523 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005525 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5526 (ulong)asc_dvc_varp, (ulong)qdonep);
5527 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005529 /*
5530 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5531 * command that has been completed.
5532 */
5533 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5534 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005536 if (scp == NULL) {
5537 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5538 return;
5539 }
5540 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005542 /*
5543 * If the request's host pointer is not valid, display a
5544 * message and return.
5545 */
5546 shost = scp->device->host;
5547 for (i = 0; i < asc_board_count; i++) {
5548 if (asc_host[i] == shost) {
5549 break;
5550 }
5551 }
5552 if (i == asc_board_count) {
5553 ASC_PRINT2
5554 ("asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
5555 (ulong)scp, (ulong)shost);
5556 return;
5557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005559 ASC_STATS(shost, callback);
5560 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005562 /*
5563 * If the request isn't found on the active queue, it may
5564 * have been removed to handle a reset request.
5565 * Display a message and return.
5566 */
5567 boardp = ASC_BOARDP(shost);
5568 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5569 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5570 ASC_PRINT2
5571 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5572 boardp->id, (ulong)scp);
5573 return;
5574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005576 /*
5577 * 'qdonep' contains the command's ending status.
5578 */
5579 switch (qdonep->d3.done_stat) {
5580 case QD_NO_ERROR:
5581 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5582 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005584 /*
5585 * If an INQUIRY command completed successfully, then call
5586 * the AscInquiryHandling() function to set-up the device.
5587 */
5588 if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
5589 (scp->request_bufflen - qdonep->remain_bytes) >= 8) {
5590 AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
5591 (ASC_SCSI_INQUIRY *)scp->
5592 request_buffer);
5593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005594
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005595 /*
5596 * Check for an underrun condition.
5597 *
5598 * If there was no error and an underrun condition, then
5599 * then return the number of underrun bytes.
5600 */
5601 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5602 qdonep->remain_bytes <= scp->request_bufflen) {
5603 ASC_DBG1(1,
5604 "asc_isr_callback: underrun condition %u bytes\n",
5605 (unsigned)qdonep->remain_bytes);
5606 scp->resid = qdonep->remain_bytes;
5607 }
5608 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005610 case QD_WITH_ERROR:
5611 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5612 switch (qdonep->d3.host_stat) {
5613 case QHSTA_NO_ERROR:
5614 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5615 ASC_DBG(2,
5616 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5617 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5618 sizeof(scp->sense_buffer));
5619 /*
5620 * Note: The 'status_byte()' macro used by target drivers
5621 * defined in scsi.h shifts the status byte returned by
5622 * host drivers right by 1 bit. This is why target drivers
5623 * also use right shifted status byte definitions. For
5624 * instance target drivers use CHECK_CONDITION, defined to
5625 * 0x1, instead of the SCSI defined check condition value
5626 * of 0x2. Host drivers are supposed to return the status
5627 * byte as it is defined by SCSI.
5628 */
5629 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5630 STATUS_BYTE(qdonep->d3.scsi_stat);
5631 } else {
5632 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5633 }
5634 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005636 default:
5637 /* QHSTA error occurred */
5638 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5639 qdonep->d3.host_stat);
5640 scp->result = HOST_BYTE(DID_BAD_TARGET);
5641 break;
5642 }
5643 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005645 case QD_ABORTED_BY_HOST:
5646 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5647 scp->result =
5648 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5649 scsi_msg) |
5650 STATUS_BYTE(qdonep->d3.scsi_stat);
5651 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005653 default:
5654 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5655 qdonep->d3.done_stat);
5656 scp->result =
5657 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5658 scsi_msg) |
5659 STATUS_BYTE(qdonep->d3.scsi_stat);
5660 break;
5661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005663 /*
5664 * If the 'init_tidmask' bit isn't already set for the target and the
5665 * current request finished normally, then set the bit for the target
5666 * to indicate that a device is present.
5667 */
5668 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5669 qdonep->d3.done_stat == QD_NO_ERROR &&
5670 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5671 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5672 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005674 /*
5675 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5676 * function, add the command to the end of the board's done queue.
5677 * The done function for the command will be called from
5678 * advansys_interrupt().
5679 */
5680 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005682 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683}
5684
5685/*
5686 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5687 *
5688 * Callback function for the Wide SCSI Adv Library.
5689 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005690static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005692 asc_board_t *boardp;
5693 adv_req_t *reqp;
5694 adv_sgblk_t *sgblkp;
5695 struct scsi_cmnd *scp;
5696 struct Scsi_Host *shost;
5697 int i;
5698 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005700 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5701 (ulong)adv_dvc_varp, (ulong)scsiqp);
5702 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005704 /*
5705 * Get the adv_req_t structure for the command that has been
5706 * completed. The adv_req_t structure actually contains the
5707 * completed ADV_SCSI_REQ_Q structure.
5708 */
5709 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5710 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5711 if (reqp == NULL) {
5712 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5713 return;
5714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005716 /*
5717 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5718 * command that has been completed.
5719 *
5720 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5721 * if any, are dropped, because a board structure pointer can not be
5722 * determined.
5723 */
5724 scp = reqp->cmndp;
5725 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5726 if (scp == NULL) {
5727 ASC_PRINT
5728 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5729 return;
5730 }
5731 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005733 /*
5734 * If the request's host pointer is not valid, display a message
5735 * and return.
5736 */
5737 shost = scp->device->host;
5738 for (i = 0; i < asc_board_count; i++) {
5739 if (asc_host[i] == shost) {
5740 break;
5741 }
5742 }
5743 /*
5744 * Note: If the host structure is not found, the adv_req_t request
5745 * structure and adv_sgblk_t structure, if any, is dropped.
5746 */
5747 if (i == asc_board_count) {
5748 ASC_PRINT2
5749 ("adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
5750 (ulong)scp, (ulong)shost);
5751 return;
5752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005754 ASC_STATS(shost, callback);
5755 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005757 /*
5758 * If the request isn't found on the active queue, it may have been
5759 * removed to handle a reset request. Display a message and return.
5760 *
5761 * Note: Because the structure may still be in use don't attempt
5762 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5763 */
5764 boardp = ASC_BOARDP(shost);
5765 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5766 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5767 ASC_PRINT2
5768 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5769 boardp->id, (ulong)scp);
5770 return;
5771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005773 /*
5774 * 'done_status' contains the command's ending status.
5775 */
5776 switch (scsiqp->done_status) {
5777 case QD_NO_ERROR:
5778 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5779 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005781 /*
5782 * Check for an underrun condition.
5783 *
5784 * If there was no error and an underrun condition, then
5785 * then return the number of underrun bytes.
5786 */
5787 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5788 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5789 resid_cnt <= scp->request_bufflen) {
5790 ASC_DBG1(1,
5791 "adv_isr_callback: underrun condition %lu bytes\n",
5792 (ulong)resid_cnt);
5793 scp->resid = resid_cnt;
5794 }
5795 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005797 case QD_WITH_ERROR:
5798 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5799 switch (scsiqp->host_status) {
5800 case QHSTA_NO_ERROR:
5801 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5802 ASC_DBG(2,
5803 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5804 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5805 sizeof(scp->sense_buffer));
5806 /*
5807 * Note: The 'status_byte()' macro used by target drivers
5808 * defined in scsi.h shifts the status byte returned by
5809 * host drivers right by 1 bit. This is why target drivers
5810 * also use right shifted status byte definitions. For
5811 * instance target drivers use CHECK_CONDITION, defined to
5812 * 0x1, instead of the SCSI defined check condition value
5813 * of 0x2. Host drivers are supposed to return the status
5814 * byte as it is defined by SCSI.
5815 */
5816 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5817 STATUS_BYTE(scsiqp->scsi_status);
5818 } else {
5819 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5820 }
5821 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005823 default:
5824 /* Some other QHSTA error occurred. */
5825 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5826 scsiqp->host_status);
5827 scp->result = HOST_BYTE(DID_BAD_TARGET);
5828 break;
5829 }
5830 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005832 case QD_ABORTED_BY_HOST:
5833 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5834 scp->result =
5835 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5836 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005838 default:
5839 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5840 scsiqp->done_status);
5841 scp->result =
5842 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5843 break;
5844 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005846 /*
5847 * If the 'init_tidmask' bit isn't already set for the target and the
5848 * current request finished normally, then set the bit for the target
5849 * to indicate that a device is present.
5850 */
5851 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5852 scsiqp->done_status == QD_NO_ERROR &&
5853 scsiqp->host_status == QHSTA_NO_ERROR) {
5854 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005857 /*
5858 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5859 * function, add the command to the end of the board's done queue.
5860 * The done function for the command will be called from
5861 * advansys_interrupt().
5862 */
5863 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005865 /*
5866 * Free all 'adv_sgblk_t' structures allocated for the request.
5867 */
5868 while ((sgblkp = reqp->sgblkp) != NULL) {
5869 /* Remove 'sgblkp' from the request list. */
5870 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005872 /* Add 'sgblkp' to the board free list. */
5873 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5874 boardp->adv_sgblkp = sgblkp;
5875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005877 /*
5878 * Free the adv_req_t structure used with the command by adding
5879 * it back to the board free list.
5880 */
5881 reqp->next_reqp = boardp->adv_reqp;
5882 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005884 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005886 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887}
5888
5889/*
5890 * adv_async_callback() - Adv Library asynchronous event callback function.
5891 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005892static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005894 switch (code) {
5895 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5896 /*
5897 * The firmware detected a SCSI Bus reset.
5898 */
5899 ASC_DBG(0,
5900 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5901 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005903 case ADV_ASYNC_RDMA_FAILURE:
5904 /*
5905 * Handle RDMA failure by resetting the SCSI Bus and
5906 * possibly the chip if it is unresponsive. Log the error
5907 * with a unique code.
5908 */
5909 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5910 AdvResetChipAndSB(adv_dvc_varp);
5911 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005913 case ADV_HOST_SCSI_BUS_RESET:
5914 /*
5915 * Host generated SCSI bus reset occurred.
5916 */
5917 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5918 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005920 default:
5921 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5922 break;
5923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924}
5925
5926/*
5927 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5928 * to indicate a command is queued for the device.
5929 *
5930 * 'flag' may be either ASC_FRONT or ASC_BACK.
5931 *
5932 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5933 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005934static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005936 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005938 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5939 (ulong)ascq, (ulong)reqp, flag);
5940 ASC_ASSERT(reqp != NULL);
5941 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5942 tid = REQPTID(reqp);
5943 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5944 if (flag == ASC_FRONT) {
5945 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5946 ascq->q_first[tid] = reqp;
5947 /* If the queue was empty, set the last pointer. */
5948 if (ascq->q_last[tid] == NULL) {
5949 ascq->q_last[tid] = reqp;
5950 }
5951 } else { /* ASC_BACK */
5952 if (ascq->q_last[tid] != NULL) {
5953 ascq->q_last[tid]->host_scribble =
5954 (unsigned char *)reqp;
5955 }
5956 ascq->q_last[tid] = reqp;
5957 reqp->host_scribble = NULL;
5958 /* If the queue was empty, set the first pointer. */
5959 if (ascq->q_first[tid] == NULL) {
5960 ascq->q_first[tid] = reqp;
5961 }
5962 }
5963 /* The queue has at least one entry, set its bit. */
5964 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005966 /* Maintain request queue statistics. */
5967 ascq->q_tot_cnt[tid]++;
5968 ascq->q_cur_cnt[tid]++;
5969 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5970 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5971 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5972 tid, ascq->q_max_cnt[tid]);
5973 }
5974 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005976 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5977 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978}
5979
5980/*
5981 * Return first queued 'REQP' on the specified queue for
5982 * the specified target device. Clear the 'tidmask' bit for
5983 * the device if no more commands are left queued for it.
5984 *
5985 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5986 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005987static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005989 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005991 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5992 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5993 if ((reqp = ascq->q_first[tid]) != NULL) {
5994 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5995 ascq->q_first[tid] = REQPNEXT(reqp);
5996 /* If the queue is empty, clear its bit and the last pointer. */
5997 if (ascq->q_first[tid] == NULL) {
5998 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5999 ASC_ASSERT(ascq->q_last[tid] == reqp);
6000 ascq->q_last[tid] = NULL;
6001 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006003 /* Maintain request queue statistics. */
6004 ascq->q_cur_cnt[tid]--;
6005 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
6006 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006008 }
6009 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
6010 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011}
6012
6013/*
6014 * Return a pointer to a singly linked list of all the requests queued
6015 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
6016 *
6017 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
6018 * the last request returned in the singly linked list.
6019 *
6020 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
6021 * then all queued requests are concatenated into one list and
6022 * returned.
6023 *
6024 * Note: If 'lastpp' is used to append a new list to the end of
6025 * an old list, only change the old list last pointer if '*lastpp'
6026 * (or the function return value) is not NULL, i.e. use a temporary
6027 * variable for 'lastpp' and check its value after the function return
6028 * before assigning it to the list last pointer.
6029 *
6030 * Unfortunately collecting queuing time statistics adds overhead to
6031 * the function that isn't inherent to the function's algorithm.
6032 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006033static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006035 REQP firstp, lastp;
6036 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006038 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
6039 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006041 /*
6042 * If 'tid' is not ASC_TID_ALL, return requests only for
6043 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
6044 * requests for all tids.
6045 */
6046 if (tid != ASC_TID_ALL) {
6047 /* Return all requests for the specified 'tid'. */
6048 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
6049 /* List is empty; Set first and last return pointers to NULL. */
6050 firstp = lastp = NULL;
6051 } else {
6052 firstp = ascq->q_first[tid];
6053 lastp = ascq->q_last[tid];
6054 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
6055 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006057 {
6058 REQP reqp;
6059 ascq->q_cur_cnt[tid] = 0;
6060 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
6061 REQTIMESTAT("asc_dequeue_list", ascq,
6062 reqp, tid);
6063 }
6064 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006065#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006066 }
6067 } else {
6068 /* Return all requests for all tids. */
6069 firstp = lastp = NULL;
6070 for (i = 0; i <= ADV_MAX_TID; i++) {
6071 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
6072 if (firstp == NULL) {
6073 firstp = ascq->q_first[i];
6074 lastp = ascq->q_last[i];
6075 } else {
6076 ASC_ASSERT(lastp != NULL);
6077 lastp->host_scribble =
6078 (unsigned char *)ascq->q_first[i];
6079 lastp = ascq->q_last[i];
6080 }
6081 ascq->q_first[i] = ascq->q_last[i] = NULL;
6082 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006084 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006086 }
6087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006089 {
6090 REQP reqp;
6091 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
6092 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
6093 reqp->device->id);
6094 }
6095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006097 }
6098 if (lastpp) {
6099 *lastpp = lastp;
6100 }
6101 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
6102 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103}
6104
6105/*
6106 * Remove the specified 'REQP' from the specified queue for
6107 * the specified target device. Clear the 'tidmask' bit for the
6108 * device if no more commands are left queued for it.
6109 *
6110 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
6111 *
6112 * Return ASC_TRUE if the command was found and removed,
6113 * otherwise return ASC_FALSE.
6114 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006115static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006117 REQP currp, prevp;
6118 int tid;
6119 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006121 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
6122 (ulong)ascq, (ulong)reqp);
6123 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006125 tid = REQPTID(reqp);
6126 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006128 /*
6129 * Handle the common case of 'reqp' being the first
6130 * entry on the queue.
6131 */
6132 if (reqp == ascq->q_first[tid]) {
6133 ret = ASC_TRUE;
6134 ascq->q_first[tid] = REQPNEXT(reqp);
6135 /* If the queue is now empty, clear its bit and the last pointer. */
6136 if (ascq->q_first[tid] == NULL) {
6137 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
6138 ASC_ASSERT(ascq->q_last[tid] == reqp);
6139 ascq->q_last[tid] = NULL;
6140 }
6141 } else if (ascq->q_first[tid] != NULL) {
6142 ASC_ASSERT(ascq->q_last[tid] != NULL);
6143 /*
6144 * Because the case of 'reqp' being the first entry has been
6145 * handled above and it is known the queue is not empty, if
6146 * 'reqp' is found on the queue it is guaranteed the queue will
6147 * not become empty and that 'q_first[tid]' will not be changed.
6148 *
6149 * Set 'prevp' to the first entry, 'currp' to the second entry,
6150 * and search for 'reqp'.
6151 */
6152 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
6153 currp; prevp = currp, currp = REQPNEXT(currp)) {
6154 if (currp == reqp) {
6155 ret = ASC_TRUE;
6156 prevp->host_scribble =
6157 (unsigned char *)REQPNEXT(currp);
6158 reqp->host_scribble = NULL;
6159 if (ascq->q_last[tid] == reqp) {
6160 ascq->q_last[tid] = prevp;
6161 }
6162 break;
6163 }
6164 }
6165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006167 /* Maintain request queue statistics. */
6168 if (ret == ASC_TRUE) {
6169 ascq->q_cur_cnt[tid]--;
6170 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
6171 }
6172 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006174 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
6175 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176}
6177
6178/*
6179 * Execute as many queued requests as possible for the specified queue.
6180 *
6181 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
6182 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006183static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006184{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006185 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
6186 REQP reqp;
6187 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006188
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006189 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
6190 /*
6191 * Execute queued commands for devices attached to
6192 * the current board in round-robin fashion.
6193 */
6194 scan_tidmask = ascq->q_tidmask;
6195 do {
6196 for (i = 0; i <= ADV_MAX_TID; i++) {
6197 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
6198 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
6199 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6200 } else
6201 if (asc_execute_scsi_cmnd
6202 ((struct scsi_cmnd *)reqp)
6203 == ASC_BUSY) {
6204 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6205 /*
6206 * The request returned ASC_BUSY. Enqueue at the front of
6207 * target's waiting list to maintain correct ordering.
6208 */
6209 asc_enqueue(ascq, reqp, ASC_FRONT);
6210 }
6211 }
6212 }
6213 } while (scan_tidmask);
6214 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215}
6216
6217#ifdef CONFIG_PROC_FS
6218/*
6219 * asc_prt_board_devices()
6220 *
6221 * Print driver information for devices attached to the board.
6222 *
6223 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6224 * cf. asc_prt_line().
6225 *
6226 * Return the number of characters copied into 'cp'. No more than
6227 * 'cplen' characters will be copied to 'cp'.
6228 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006229static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006231 asc_board_t *boardp;
6232 int leftlen;
6233 int totlen;
6234 int len;
6235 int chip_scsi_id;
6236 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006238 boardp = ASC_BOARDP(shost);
6239 leftlen = cplen;
6240 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006242 len = asc_prt_line(cp, leftlen,
6243 "\nDevice Information for AdvanSys SCSI Host %d:\n",
6244 shost->host_no);
6245 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006247 if (ASC_NARROW_BOARD(boardp)) {
6248 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6249 } else {
6250 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006253 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6254 ASC_PRT_NEXT();
6255 for (i = 0; i <= ADV_MAX_TID; i++) {
6256 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6257 len = asc_prt_line(cp, leftlen, " %X,", i);
6258 ASC_PRT_NEXT();
6259 }
6260 }
6261 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6262 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006263
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006264 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265}
6266
6267/*
6268 * Display Wide Board BIOS Information.
6269 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006270static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006272 asc_board_t *boardp;
6273 int leftlen;
6274 int totlen;
6275 int len;
6276 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006278 boardp = ASC_BOARDP(shost);
6279 leftlen = cplen;
6280 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006281
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006282 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6283 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006285 /*
6286 * If the BIOS saved a valid signature, then fill in
6287 * the BIOS code segment base address.
6288 */
6289 if (boardp->bios_signature != 0x55AA) {
6290 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6291 ASC_PRT_NEXT();
6292 len = asc_prt_line(cp, leftlen,
6293 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6294 ASC_PRT_NEXT();
6295 len = asc_prt_line(cp, leftlen,
6296 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6297 ASC_PRT_NEXT();
6298 } else {
6299 major = (boardp->bios_version >> 12) & 0xF;
6300 minor = (boardp->bios_version >> 8) & 0xF;
6301 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006303 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6304 major, minor,
6305 letter >= 26 ? '?' : letter + 'A');
6306 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006308 /*
6309 * Current available ROM BIOS release is 3.1I for UW
6310 * and 3.2I for U2W. This code doesn't differentiate
6311 * UW and U2W boards.
6312 */
6313 if (major < 3 || (major <= 3 && minor < 1) ||
6314 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6315 len = asc_prt_line(cp, leftlen,
6316 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6317 ASC_PRT_NEXT();
6318 len = asc_prt_line(cp, leftlen,
6319 "ftp://ftp.connectcom.net/pub\n");
6320 ASC_PRT_NEXT();
6321 }
6322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006324 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325}
6326
6327/*
6328 * Add serial number to information bar if signature AAh
6329 * is found in at bit 15-9 (7 bits) of word 1.
6330 *
6331 * Serial Number consists fo 12 alpha-numeric digits.
6332 *
6333 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6334 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6335 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6336 * 5 - Product revision (A-J) Word0: " "
6337 *
6338 * Signature Word1: 15-9 (7 bits)
6339 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6340 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6341 *
6342 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6343 *
6344 * Note 1: Only production cards will have a serial number.
6345 *
6346 * Note 2: Signature is most significant 7 bits (0xFE).
6347 *
6348 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6349 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006350static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006352 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006354 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6355 return ASC_FALSE;
6356 } else {
6357 /*
6358 * First word - 6 digits.
6359 */
6360 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006361
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006362 /* Product type - 1st digit. */
6363 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6364 /* Product type is P=Prototype */
6365 *cp += 0x8;
6366 }
6367 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006369 /* Manufacturing location - 2nd digit. */
6370 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006371
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006372 /* Product ID - 3rd, 4th digits. */
6373 num = w & 0x3FF;
6374 *cp++ = '0' + (num / 100);
6375 num %= 100;
6376 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006378 /* Product revision - 5th digit. */
6379 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006381 /*
6382 * Second word
6383 */
6384 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006386 /*
6387 * Year - 6th digit.
6388 *
6389 * If bit 15 of third word is set, then the
6390 * last digit of the year is greater than 7.
6391 */
6392 if (serialnum[2] & 0x8000) {
6393 *cp++ = '8' + ((w & 0x1C0) >> 6);
6394 } else {
6395 *cp++ = '0' + ((w & 0x1C0) >> 6);
6396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006398 /* Week of year - 7th, 8th digits. */
6399 num = w & 0x003F;
6400 *cp++ = '0' + num / 10;
6401 num %= 10;
6402 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006404 /*
6405 * Third word
6406 */
6407 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006409 /* Serial number - 9th digit. */
6410 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006411
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006412 /* 10th, 11th, 12th digits. */
6413 num = w % 1000;
6414 *cp++ = '0' + num / 100;
6415 num %= 100;
6416 *cp++ = '0' + num / 10;
6417 num %= 10;
6418 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006420 *cp = '\0'; /* Null Terminate the string. */
6421 return ASC_TRUE;
6422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006423}
6424
6425/*
6426 * asc_prt_asc_board_eeprom()
6427 *
6428 * Print board EEPROM configuration.
6429 *
6430 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6431 * cf. asc_prt_line().
6432 *
6433 * Return the number of characters copied into 'cp'. No more than
6434 * 'cplen' characters will be copied to 'cp'.
6435 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006436static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006437{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006438 asc_board_t *boardp;
6439 ASC_DVC_VAR *asc_dvc_varp;
6440 int leftlen;
6441 int totlen;
6442 int len;
6443 ASCEEP_CONFIG *ep;
6444 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006446 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006448 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006450 boardp = ASC_BOARDP(shost);
6451 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6452 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006453
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006454 leftlen = cplen;
6455 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006457 len = asc_prt_line(cp, leftlen,
6458 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6459 shost->host_no);
6460 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006461
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006462 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6463 == ASC_TRUE) {
6464 len =
6465 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6466 serialstr);
6467 ASC_PRT_NEXT();
6468 } else {
6469 if (ep->adapter_info[5] == 0xBB) {
6470 len = asc_prt_line(cp, leftlen,
6471 " Default Settings Used for EEPROM-less Adapter.\n");
6472 ASC_PRT_NEXT();
6473 } else {
6474 len = asc_prt_line(cp, leftlen,
6475 " Serial Number Signature Not Present.\n");
6476 ASC_PRT_NEXT();
6477 }
6478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006479
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006480 len = asc_prt_line(cp, leftlen,
6481 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6482 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6483 ep->max_tag_qng);
6484 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006485
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006486 len = asc_prt_line(cp, leftlen,
6487 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6488 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006489
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006490 len = asc_prt_line(cp, leftlen, " Target ID: ");
6491 ASC_PRT_NEXT();
6492 for (i = 0; i <= ASC_MAX_TID; i++) {
6493 len = asc_prt_line(cp, leftlen, " %d", i);
6494 ASC_PRT_NEXT();
6495 }
6496 len = asc_prt_line(cp, leftlen, "\n");
6497 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006498
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006499 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6500 ASC_PRT_NEXT();
6501 for (i = 0; i <= ASC_MAX_TID; i++) {
6502 len = asc_prt_line(cp, leftlen, " %c",
6503 (ep->
6504 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6505 'N');
6506 ASC_PRT_NEXT();
6507 }
6508 len = asc_prt_line(cp, leftlen, "\n");
6509 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006510
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006511 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6512 ASC_PRT_NEXT();
6513 for (i = 0; i <= ASC_MAX_TID; i++) {
6514 len = asc_prt_line(cp, leftlen, " %c",
6515 (ep->
6516 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6517 'N');
6518 ASC_PRT_NEXT();
6519 }
6520 len = asc_prt_line(cp, leftlen, "\n");
6521 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006522
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006523 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6524 ASC_PRT_NEXT();
6525 for (i = 0; i <= ASC_MAX_TID; i++) {
6526 len = asc_prt_line(cp, leftlen, " %c",
6527 (ep->
6528 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6529 'N');
6530 ASC_PRT_NEXT();
6531 }
6532 len = asc_prt_line(cp, leftlen, "\n");
6533 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006534
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006535 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6536 ASC_PRT_NEXT();
6537 for (i = 0; i <= ASC_MAX_TID; i++) {
6538 len = asc_prt_line(cp, leftlen, " %c",
6539 (ep->
6540 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6541 'N');
6542 ASC_PRT_NEXT();
6543 }
6544 len = asc_prt_line(cp, leftlen, "\n");
6545 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006546
6547#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006548 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6549 len = asc_prt_line(cp, leftlen,
6550 " Host ISA DMA speed: %d MB/S\n",
6551 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6552 ASC_PRT_NEXT();
6553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554#endif /* CONFIG_ISA */
6555
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006556 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006557}
6558
6559/*
6560 * asc_prt_adv_board_eeprom()
6561 *
6562 * Print board EEPROM configuration.
6563 *
6564 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6565 * cf. asc_prt_line().
6566 *
6567 * Return the number of characters copied into 'cp'. No more than
6568 * 'cplen' characters will be copied to 'cp'.
6569 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006570static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006571{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006572 asc_board_t *boardp;
6573 ADV_DVC_VAR *adv_dvc_varp;
6574 int leftlen;
6575 int totlen;
6576 int len;
6577 int i;
6578 char *termstr;
6579 uchar serialstr[13];
6580 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6581 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6582 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6583 ushort word;
6584 ushort *wordp;
6585 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006586
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006587 boardp = ASC_BOARDP(shost);
6588 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6589 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6590 ep_3550 = &boardp->eep_config.adv_3550_eep;
6591 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6592 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6593 } else {
6594 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006596
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006597 leftlen = cplen;
6598 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006599
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006600 len = asc_prt_line(cp, leftlen,
6601 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6602 shost->host_no);
6603 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006604
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006605 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6606 wordp = &ep_3550->serial_number_word1;
6607 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6608 wordp = &ep_38C0800->serial_number_word1;
6609 } else {
6610 wordp = &ep_38C1600->serial_number_word1;
6611 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006612
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006613 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6614 len =
6615 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6616 serialstr);
6617 ASC_PRT_NEXT();
6618 } else {
6619 len = asc_prt_line(cp, leftlen,
6620 " Serial Number Signature Not Present.\n");
6621 ASC_PRT_NEXT();
6622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006623
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006624 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6625 len = asc_prt_line(cp, leftlen,
6626 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6627 ep_3550->adapter_scsi_id,
6628 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6629 ASC_PRT_NEXT();
6630 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6631 len = asc_prt_line(cp, leftlen,
6632 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6633 ep_38C0800->adapter_scsi_id,
6634 ep_38C0800->max_host_qng,
6635 ep_38C0800->max_dvc_qng);
6636 ASC_PRT_NEXT();
6637 } else {
6638 len = asc_prt_line(cp, leftlen,
6639 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6640 ep_38C1600->adapter_scsi_id,
6641 ep_38C1600->max_host_qng,
6642 ep_38C1600->max_dvc_qng);
6643 ASC_PRT_NEXT();
6644 }
6645 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6646 word = ep_3550->termination;
6647 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6648 word = ep_38C0800->termination_lvd;
6649 } else {
6650 word = ep_38C1600->termination_lvd;
6651 }
6652 switch (word) {
6653 case 1:
6654 termstr = "Low Off/High Off";
6655 break;
6656 case 2:
6657 termstr = "Low Off/High On";
6658 break;
6659 case 3:
6660 termstr = "Low On/High On";
6661 break;
6662 default:
6663 case 0:
6664 termstr = "Automatic";
6665 break;
6666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006668 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6669 len = asc_prt_line(cp, leftlen,
6670 " termination: %u (%s), bios_ctrl: 0x%x\n",
6671 ep_3550->termination, termstr,
6672 ep_3550->bios_ctrl);
6673 ASC_PRT_NEXT();
6674 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6675 len = asc_prt_line(cp, leftlen,
6676 " termination: %u (%s), bios_ctrl: 0x%x\n",
6677 ep_38C0800->termination_lvd, termstr,
6678 ep_38C0800->bios_ctrl);
6679 ASC_PRT_NEXT();
6680 } else {
6681 len = asc_prt_line(cp, leftlen,
6682 " termination: %u (%s), bios_ctrl: 0x%x\n",
6683 ep_38C1600->termination_lvd, termstr,
6684 ep_38C1600->bios_ctrl);
6685 ASC_PRT_NEXT();
6686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006687
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006688 len = asc_prt_line(cp, leftlen, " Target ID: ");
6689 ASC_PRT_NEXT();
6690 for (i = 0; i <= ADV_MAX_TID; i++) {
6691 len = asc_prt_line(cp, leftlen, " %X", i);
6692 ASC_PRT_NEXT();
6693 }
6694 len = asc_prt_line(cp, leftlen, "\n");
6695 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006696
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006697 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6698 word = ep_3550->disc_enable;
6699 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6700 word = ep_38C0800->disc_enable;
6701 } else {
6702 word = ep_38C1600->disc_enable;
6703 }
6704 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6705 ASC_PRT_NEXT();
6706 for (i = 0; i <= ADV_MAX_TID; i++) {
6707 len = asc_prt_line(cp, leftlen, " %c",
6708 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
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->tagqng_able;
6716 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6717 word = ep_38C0800->tagqng_able;
6718 } else {
6719 word = ep_38C1600->tagqng_able;
6720 }
6721 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
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->start_motor;
6733 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6734 word = ep_38C0800->start_motor;
6735 } else {
6736 word = ep_38C1600->start_motor;
6737 }
6738 len = asc_prt_line(cp, leftlen, " Start Motor: ");
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 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6750 ASC_PRT_NEXT();
6751 for (i = 0; i <= ADV_MAX_TID; i++) {
6752 len = asc_prt_line(cp, leftlen, " %c",
6753 (ep_3550->
6754 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6755 'Y' : 'N');
6756 ASC_PRT_NEXT();
6757 }
6758 len = asc_prt_line(cp, leftlen, "\n");
6759 ASC_PRT_NEXT();
6760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006762 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6763 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6764 ASC_PRT_NEXT();
6765 for (i = 0; i <= ADV_MAX_TID; i++) {
6766 len = asc_prt_line(cp, leftlen, " %c",
6767 (ep_3550->
6768 ultra_able & ADV_TID_TO_TIDMASK(i))
6769 ? 'Y' : 'N');
6770 ASC_PRT_NEXT();
6771 }
6772 len = asc_prt_line(cp, leftlen, "\n");
6773 ASC_PRT_NEXT();
6774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006776 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6777 word = ep_3550->wdtr_able;
6778 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6779 word = ep_38C0800->wdtr_able;
6780 } else {
6781 word = ep_38C1600->wdtr_able;
6782 }
6783 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6784 ASC_PRT_NEXT();
6785 for (i = 0; i <= ADV_MAX_TID; i++) {
6786 len = asc_prt_line(cp, leftlen, " %c",
6787 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6788 ASC_PRT_NEXT();
6789 }
6790 len = asc_prt_line(cp, leftlen, "\n");
6791 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006792
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006793 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6794 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6795 len = asc_prt_line(cp, leftlen,
6796 " Synchronous Transfer Speed (Mhz):\n ");
6797 ASC_PRT_NEXT();
6798 for (i = 0; i <= ADV_MAX_TID; i++) {
6799 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006801 if (i == 0) {
6802 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6803 } else if (i == 4) {
6804 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6805 } else if (i == 8) {
6806 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6807 } else if (i == 12) {
6808 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6809 }
6810 switch (sdtr_speed & ADV_MAX_TID) {
6811 case 0:
6812 speed_str = "Off";
6813 break;
6814 case 1:
6815 speed_str = " 5";
6816 break;
6817 case 2:
6818 speed_str = " 10";
6819 break;
6820 case 3:
6821 speed_str = " 20";
6822 break;
6823 case 4:
6824 speed_str = " 40";
6825 break;
6826 case 5:
6827 speed_str = " 80";
6828 break;
6829 default:
6830 speed_str = "Unk";
6831 break;
6832 }
6833 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6834 ASC_PRT_NEXT();
6835 if (i == 7) {
6836 len = asc_prt_line(cp, leftlen, "\n ");
6837 ASC_PRT_NEXT();
6838 }
6839 sdtr_speed >>= 4;
6840 }
6841 len = asc_prt_line(cp, leftlen, "\n");
6842 ASC_PRT_NEXT();
6843 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006844
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006845 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006846}
6847
6848/*
6849 * asc_prt_driver_conf()
6850 *
6851 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6852 * cf. asc_prt_line().
6853 *
6854 * Return the number of characters copied into 'cp'. No more than
6855 * 'cplen' characters will be copied to 'cp'.
6856 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006857static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006858{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006859 asc_board_t *boardp;
6860 int leftlen;
6861 int totlen;
6862 int len;
6863 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006864
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006865 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006866
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006867 leftlen = cplen;
6868 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006869
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006870 len = asc_prt_line(cp, leftlen,
6871 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6872 shost->host_no);
6873 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006874
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006875 len = asc_prt_line(cp, leftlen,
6876 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6877 shost->host_busy, shost->last_reset, shost->max_id,
6878 shost->max_lun, shost->max_channel);
6879 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006880
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006881 len = asc_prt_line(cp, leftlen,
6882 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6883 shost->unique_id, shost->can_queue, shost->this_id,
6884 shost->sg_tablesize, shost->cmd_per_lun);
6885 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006887 len = asc_prt_line(cp, leftlen,
6888 " unchecked_isa_dma %d, use_clustering %d\n",
6889 shost->unchecked_isa_dma, shost->use_clustering);
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 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6894 boardp->flags, boardp->last_reset, jiffies,
6895 boardp->asc_n_io_port);
6896 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006897
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006898 /* 'shost->n_io_port' may be truncated because it is only one byte. */
6899 len = asc_prt_line(cp, leftlen,
6900 " io_port 0x%x, n_io_port 0x%x\n",
6901 shost->io_port, shost->n_io_port);
6902 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006903
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006904 if (ASC_NARROW_BOARD(boardp)) {
6905 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6906 } else {
6907 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6908 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006909
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006910 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006911}
6912
6913/*
6914 * asc_prt_asc_board_info()
6915 *
6916 * Print dynamic board configuration information.
6917 *
6918 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6919 * cf. asc_prt_line().
6920 *
6921 * Return the number of characters copied into 'cp'. No more than
6922 * 'cplen' characters will be copied to 'cp'.
6923 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006924static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006925{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006926 asc_board_t *boardp;
6927 int chip_scsi_id;
6928 int leftlen;
6929 int totlen;
6930 int len;
6931 ASC_DVC_VAR *v;
6932 ASC_DVC_CFG *c;
6933 int i;
6934 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006936 boardp = ASC_BOARDP(shost);
6937 v = &boardp->dvc_var.asc_dvc_var;
6938 c = &boardp->dvc_cfg.asc_dvc_cfg;
6939 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006940
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006941 leftlen = cplen;
6942 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006944 len = asc_prt_line(cp, leftlen,
6945 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6946 shost->host_no);
6947 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006948
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006949 len = asc_prt_line(cp, leftlen,
6950 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6951 c->chip_version, c->lib_version, c->lib_serial_no,
6952 c->mcode_date);
6953 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006954
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006955 len = asc_prt_line(cp, leftlen,
6956 " mcode_version 0x%x, err_code %u\n",
6957 c->mcode_version, v->err_code);
6958 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006959
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006960 /* Current number of commands waiting for the host. */
6961 len = asc_prt_line(cp, leftlen,
6962 " Total Command Pending: %d\n", v->cur_total_qng);
6963 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006964
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006965 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6966 ASC_PRT_NEXT();
6967 for (i = 0; i <= ASC_MAX_TID; i++) {
6968 if ((chip_scsi_id == i) ||
6969 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6970 continue;
6971 }
6972 len = asc_prt_line(cp, leftlen, " %X:%c",
6973 i,
6974 (v->
6975 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6976 'Y' : 'N');
6977 ASC_PRT_NEXT();
6978 }
6979 len = asc_prt_line(cp, leftlen, "\n");
6980 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006981
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006982 /* Current number of commands waiting for a device. */
6983 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6984 ASC_PRT_NEXT();
6985 for (i = 0; i <= ASC_MAX_TID; i++) {
6986 if ((chip_scsi_id == i) ||
6987 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6988 continue;
6989 }
6990 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6991 ASC_PRT_NEXT();
6992 }
6993 len = asc_prt_line(cp, leftlen, "\n");
6994 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006995
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006996 /* Current limit on number of commands that can be sent to a device. */
6997 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6998 ASC_PRT_NEXT();
6999 for (i = 0; i <= ASC_MAX_TID; i++) {
7000 if ((chip_scsi_id == i) ||
7001 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7002 continue;
7003 }
7004 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
7005 ASC_PRT_NEXT();
7006 }
7007 len = asc_prt_line(cp, leftlen, "\n");
7008 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007009
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007010 /* Indicate whether the device has returned queue full status. */
7011 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
7012 ASC_PRT_NEXT();
7013 for (i = 0; i <= ASC_MAX_TID; i++) {
7014 if ((chip_scsi_id == i) ||
7015 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7016 continue;
7017 }
7018 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
7019 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
7020 i, boardp->queue_full_cnt[i]);
7021 } else {
7022 len = asc_prt_line(cp, leftlen, " %X:N", i);
7023 }
7024 ASC_PRT_NEXT();
7025 }
7026 len = asc_prt_line(cp, leftlen, "\n");
7027 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007029 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
7030 ASC_PRT_NEXT();
7031 for (i = 0; i <= ASC_MAX_TID; i++) {
7032 if ((chip_scsi_id == i) ||
7033 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7034 continue;
7035 }
7036 len = asc_prt_line(cp, leftlen, " %X:%c",
7037 i,
7038 (v->
7039 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7040 'N');
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 for (i = 0; i <= ASC_MAX_TID; i++) {
7047 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007048
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007049 if ((chip_scsi_id == i) ||
7050 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7051 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
7052 continue;
7053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007054
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007055 len = asc_prt_line(cp, leftlen, " %X:", i);
7056 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007057
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007058 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
7059 len = asc_prt_line(cp, leftlen, " Asynchronous");
7060 ASC_PRT_NEXT();
7061 } else {
7062 syn_period_ix =
7063 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
7064 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007066 len = asc_prt_line(cp, leftlen,
7067 " Transfer Period Factor: %d (%d.%d Mhz),",
7068 v->sdtr_period_tbl[syn_period_ix],
7069 250 /
7070 v->sdtr_period_tbl[syn_period_ix],
7071 ASC_TENTHS(250,
7072 v->
7073 sdtr_period_tbl
7074 [syn_period_ix]));
7075 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007076
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007077 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7078 boardp->
7079 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
7080 ASC_PRT_NEXT();
7081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007083 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7084 len = asc_prt_line(cp, leftlen, "*\n");
7085 renegotiate = 1;
7086 } else {
7087 len = asc_prt_line(cp, leftlen, "\n");
7088 }
7089 ASC_PRT_NEXT();
7090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007091
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007092 if (renegotiate) {
7093 len = asc_prt_line(cp, leftlen,
7094 " * = Re-negotiation pending before next command.\n");
7095 ASC_PRT_NEXT();
7096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007097
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007098 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007099}
7100
7101/*
7102 * asc_prt_adv_board_info()
7103 *
7104 * Print dynamic board configuration information.
7105 *
7106 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7107 * cf. asc_prt_line().
7108 *
7109 * Return the number of characters copied into 'cp'. No more than
7110 * 'cplen' characters will be copied to 'cp'.
7111 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007112static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007113{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007114 asc_board_t *boardp;
7115 int leftlen;
7116 int totlen;
7117 int len;
7118 int i;
7119 ADV_DVC_VAR *v;
7120 ADV_DVC_CFG *c;
7121 AdvPortAddr iop_base;
7122 ushort chip_scsi_id;
7123 ushort lramword;
7124 uchar lrambyte;
7125 ushort tagqng_able;
7126 ushort sdtr_able, wdtr_able;
7127 ushort wdtr_done, sdtr_done;
7128 ushort period = 0;
7129 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007131 boardp = ASC_BOARDP(shost);
7132 v = &boardp->dvc_var.adv_dvc_var;
7133 c = &boardp->dvc_cfg.adv_dvc_cfg;
7134 iop_base = v->iop_base;
7135 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007137 leftlen = cplen;
7138 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007139
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007140 len = asc_prt_line(cp, leftlen,
7141 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
7142 shost->host_no);
7143 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007144
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007145 len = asc_prt_line(cp, leftlen,
7146 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
7147 v->iop_base,
7148 AdvReadWordRegister(iop_base,
7149 IOPW_SCSI_CFG1) & CABLE_DETECT,
7150 v->err_code);
7151 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007152
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007153 len = asc_prt_line(cp, leftlen,
7154 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
7155 c->chip_version, c->lib_version, c->mcode_date,
7156 c->mcode_version);
7157 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007158
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007159 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
7160 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
7161 ASC_PRT_NEXT();
7162 for (i = 0; i <= ADV_MAX_TID; i++) {
7163 if ((chip_scsi_id == i) ||
7164 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7165 continue;
7166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007167
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007168 len = asc_prt_line(cp, leftlen, " %X:%c",
7169 i,
7170 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7171 'N');
7172 ASC_PRT_NEXT();
7173 }
7174 len = asc_prt_line(cp, leftlen, "\n");
7175 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007176
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007177 len = asc_prt_line(cp, leftlen, " Queue Limit:");
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 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
7186 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007187
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007188 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
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, " Command Pending:");
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_QUEUED_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 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
7212 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
7213 ASC_PRT_NEXT();
7214 for (i = 0; i <= ADV_MAX_TID; i++) {
7215 if ((chip_scsi_id == i) ||
7216 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7217 continue;
7218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007220 len = asc_prt_line(cp, leftlen, " %X:%c",
7221 i,
7222 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7223 'N');
7224 ASC_PRT_NEXT();
7225 }
7226 len = asc_prt_line(cp, leftlen, "\n");
7227 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007228
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007229 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
7230 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
7231 ASC_PRT_NEXT();
7232 for (i = 0; i <= ADV_MAX_TID; i++) {
7233 if ((chip_scsi_id == i) ||
7234 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7235 continue;
7236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007237
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007238 AdvReadWordLram(iop_base,
7239 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7240 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007241
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007242 len = asc_prt_line(cp, leftlen, " %X:%d",
7243 i, (lramword & 0x8000) ? 16 : 8);
7244 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007245
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007246 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
7247 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7248 len = asc_prt_line(cp, leftlen, "*");
7249 ASC_PRT_NEXT();
7250 renegotiate = 1;
7251 }
7252 }
7253 len = asc_prt_line(cp, leftlen, "\n");
7254 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007255
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007256 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7257 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7258 ASC_PRT_NEXT();
7259 for (i = 0; i <= ADV_MAX_TID; i++) {
7260 if ((chip_scsi_id == i) ||
7261 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7262 continue;
7263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007264
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007265 len = asc_prt_line(cp, leftlen, " %X:%c",
7266 i,
7267 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7268 'N');
7269 ASC_PRT_NEXT();
7270 }
7271 len = asc_prt_line(cp, leftlen, "\n");
7272 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007273
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007274 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7275 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007276
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007277 AdvReadWordLram(iop_base,
7278 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7279 lramword);
7280 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007281
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007282 if ((chip_scsi_id == i) ||
7283 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7284 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7285 continue;
7286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007287
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007288 len = asc_prt_line(cp, leftlen, " %X:", i);
7289 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007291 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7292 len = asc_prt_line(cp, leftlen, " Asynchronous");
7293 ASC_PRT_NEXT();
7294 } else {
7295 len =
7296 asc_prt_line(cp, leftlen,
7297 " Transfer Period Factor: ");
7298 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007299
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007300 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7301 len =
7302 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7303 ASC_PRT_NEXT();
7304 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7305 len =
7306 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7307 ASC_PRT_NEXT();
7308 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007309
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007310 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007311
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007312 if (period == 0) { /* Should never happen. */
7313 len =
7314 asc_prt_line(cp, leftlen,
7315 "%d (? Mhz), ");
7316 ASC_PRT_NEXT();
7317 } else {
7318 len = asc_prt_line(cp, leftlen,
7319 "%d (%d.%d Mhz),",
7320 period, 250 / period,
7321 ASC_TENTHS(250,
7322 period));
7323 ASC_PRT_NEXT();
7324 }
7325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007326
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007327 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7328 lramword & 0x1F);
7329 ASC_PRT_NEXT();
7330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007331
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007332 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7333 len = asc_prt_line(cp, leftlen, "*\n");
7334 renegotiate = 1;
7335 } else {
7336 len = asc_prt_line(cp, leftlen, "\n");
7337 }
7338 ASC_PRT_NEXT();
7339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007340
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007341 if (renegotiate) {
7342 len = asc_prt_line(cp, leftlen,
7343 " * = Re-negotiation pending before next command.\n");
7344 ASC_PRT_NEXT();
7345 }
7346
7347 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007348}
7349
7350/*
7351 * asc_proc_copy()
7352 *
7353 * Copy proc information to a read buffer taking into account the current
7354 * read offset in the file and the remaining space in the read buffer.
7355 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007356static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007357asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007358 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007359{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007360 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007361
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007362 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7363 (unsigned)offset, (unsigned)advoffset, cplen);
7364 if (offset <= advoffset) {
7365 /* Read offset below current offset, copy everything. */
7366 cnt = min(cplen, leftlen);
7367 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7368 (ulong)curbuf, (ulong)cp, cnt);
7369 memcpy(curbuf, cp, cnt);
7370 } else if (offset < advoffset + cplen) {
7371 /* Read offset within current range, partial copy. */
7372 cnt = (advoffset + cplen) - offset;
7373 cp = (cp + cplen) - cnt;
7374 cnt = min(cnt, leftlen);
7375 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7376 (ulong)curbuf, (ulong)cp, cnt);
7377 memcpy(curbuf, cp, cnt);
7378 }
7379 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007380}
7381
7382/*
7383 * asc_prt_line()
7384 *
7385 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7386 *
7387 * Return 0 if printing to the console, otherwise return the number of
7388 * bytes written to the buffer.
7389 *
7390 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7391 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7392 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007393static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007394{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007395 va_list args;
7396 int ret;
7397 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007398
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007399 va_start(args, fmt);
7400 ret = vsprintf(s, fmt, args);
7401 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7402 if (buf == NULL) {
7403 (void)printk(s);
7404 ret = 0;
7405 } else {
7406 ret = min(buflen, ret);
7407 memcpy(buf, s, ret);
7408 }
7409 va_end(args);
7410 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007411}
7412#endif /* CONFIG_PROC_FS */
7413
Linus Torvalds1da177e2005-04-16 15:20:36 -07007414/*
7415 * --- Functions Required by the Asc Library
7416 */
7417
7418/*
7419 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7420 * global variable which is incremented once every 5 ms
7421 * from a timer interrupt, because this function may be
7422 * called when interrupts are disabled.
7423 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007424static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007425{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007426 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7427 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007428}
7429
7430/*
7431 * Currently and inline noop but leave as a placeholder.
7432 * Leave DvcEnterCritical() as a noop placeholder.
7433 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007434static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007435{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007436 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007437}
7438
7439/*
7440 * Critical sections are all protected by the board spinlock.
7441 * Leave DvcLeaveCritical() as a noop placeholder.
7442 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007443static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007444{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007445 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007446}
7447
7448/*
7449 * void
7450 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7451 *
7452 * Calling/Exit State:
7453 * none
7454 *
7455 * Description:
7456 * Output an ASC_SCSI_Q structure to the chip
7457 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007458static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007459DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7460{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007461 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007462
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007463 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7464 AscSetChipLramAddr(iop_base, s_addr);
7465 for (i = 0; i < 2 * words; i += 2) {
7466 if (i == 4 || i == 20) {
7467 continue;
7468 }
7469 outpw(iop_base + IOP_RAM_DATA,
7470 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007472}
7473
7474/*
7475 * void
7476 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7477 *
7478 * Calling/Exit State:
7479 * none
7480 *
7481 * Description:
7482 * Input an ASC_QDONE_INFO structure from the chip
7483 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007484static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007485DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7486{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007487 int i;
7488 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007489
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007490 AscSetChipLramAddr(iop_base, s_addr);
7491 for (i = 0; i < 2 * words; i += 2) {
7492 if (i == 10) {
7493 continue;
7494 }
7495 word = inpw(iop_base + IOP_RAM_DATA);
7496 inbuf[i] = word & 0xff;
7497 inbuf[i + 1] = (word >> 8) & 0xff;
7498 }
7499 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007500}
7501
7502/*
7503 * Read a PCI configuration byte.
7504 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007505static uchar __init DvcReadPCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007506{
7507#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007508 uchar byte_data;
7509 pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
7510 return byte_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007511#else /* !defined(CONFIG_PCI) */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007512 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007513#endif /* !defined(CONFIG_PCI) */
7514}
7515
7516/*
7517 * Write a PCI configuration byte.
7518 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007519static void __init
7520DvcWritePCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007521{
7522#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007523 pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007524#endif /* CONFIG_PCI */
7525}
7526
7527/*
7528 * Return the BIOS address of the adapter at the specified
7529 * I/O port and with the specified bus type.
7530 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007531static ushort __init AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007532{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007533 ushort cfg_lsw;
7534 ushort bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007536 /*
7537 * The PCI BIOS is re-located by the motherboard BIOS. Because
7538 * of this the driver can not determine where a PCI BIOS is
7539 * loaded and executes.
7540 */
7541 if (bus_type & ASC_IS_PCI) {
7542 return (0);
7543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007544#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007545 if ((bus_type & ASC_IS_EISA) != 0) {
7546 cfg_lsw = AscGetEisaChipCfg(iop_base);
7547 cfg_lsw &= 0x000F;
7548 bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
7549 (cfg_lsw * ASC_BIOS_BANK_SIZE));
7550 return (bios_addr);
7551 } /* if */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007552#endif /* CONFIG_ISA */
7553
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007554 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007555
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007556 /*
7557 * ISA PnP uses the top bit as the 32K BIOS flag
7558 */
7559 if (bus_type == ASC_IS_ISAPNP) {
7560 cfg_lsw &= 0x7FFF;
7561 }
7562 /* if */
7563 bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
7564 ASC_BIOS_MIN_ADDR);
7565 return (bios_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007566}
7567
Linus Torvalds1da177e2005-04-16 15:20:36 -07007568/*
7569 * --- Functions Required by the Adv Library
7570 */
7571
7572/*
7573 * DvcGetPhyAddr()
7574 *
7575 * Return the physical address of 'vaddr' and set '*lenp' to the
7576 * number of physically contiguous bytes that follow 'vaddr'.
7577 * 'flag' indicates the type of structure whose physical address
7578 * is being translated.
7579 *
7580 * Note: Because Linux currently doesn't page the kernel and all
7581 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7582 */
7583ADV_PADDR
7584DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007585 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007586{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007587 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007588
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007589 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007590
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007591 ASC_DBG4(4,
7592 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7593 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7594 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007595
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007596 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007597}
7598
7599/*
7600 * Read a PCI configuration byte.
7601 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007602static uchar __init DvcAdvReadPCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007603{
7604#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007605 uchar byte_data;
7606 pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
7607 return byte_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007608#else /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007609 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007610#endif /* CONFIG_PCI */
7611}
7612
7613/*
7614 * Write a PCI configuration byte.
7615 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007616static void __init
7617DvcAdvWritePCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007618{
7619#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007620 pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007621#else /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007622 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007623#endif /* CONFIG_PCI */
7624}
7625
7626/*
7627 * --- Tracing and Debugging Functions
7628 */
7629
7630#ifdef ADVANSYS_STATS
7631#ifdef CONFIG_PROC_FS
7632/*
7633 * asc_prt_board_stats()
7634 *
7635 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7636 * cf. asc_prt_line().
7637 *
7638 * Return the number of characters copied into 'cp'. No more than
7639 * 'cplen' characters will be copied to 'cp'.
7640 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007641static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007642{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007643 int leftlen;
7644 int totlen;
7645 int len;
7646 struct asc_stats *s;
7647 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007648
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007649 leftlen = cplen;
7650 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007651
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007652 boardp = ASC_BOARDP(shost);
7653 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007654
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007655 len = asc_prt_line(cp, leftlen,
7656 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7657 shost->host_no);
7658 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007659
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007660 len = asc_prt_line(cp, leftlen,
7661 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7662 s->queuecommand, s->reset, s->biosparam,
7663 s->interrupt);
7664 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007665
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007666 len = asc_prt_line(cp, leftlen,
7667 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7668 s->callback, s->done, s->build_error,
7669 s->adv_build_noreq, s->adv_build_nosg);
7670 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007672 len = asc_prt_line(cp, leftlen,
7673 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7674 s->exe_noerror, s->exe_busy, s->exe_error,
7675 s->exe_unknown);
7676 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007677
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007678 /*
7679 * Display data transfer statistics.
7680 */
7681 if (s->cont_cnt > 0) {
7682 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7683 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007684
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007685 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7686 s->cont_xfer / 2,
7687 ASC_TENTHS(s->cont_xfer, 2));
7688 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007689
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007690 /* Contiguous transfer average size */
7691 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7692 (s->cont_xfer / 2) / s->cont_cnt,
7693 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7694 ASC_PRT_NEXT();
7695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007696
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007697 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007698
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007699 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7700 s->sg_cnt, s->sg_elem);
7701 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007702
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007703 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7704 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7705 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007706
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007707 /* Scatter gather transfer statistics */
7708 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7709 s->sg_elem / s->sg_cnt,
7710 ASC_TENTHS(s->sg_elem, s->sg_cnt));
7711 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007712
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007713 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
7714 (s->sg_xfer / 2) / s->sg_elem,
7715 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7716 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007717
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007718 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7719 (s->sg_xfer / 2) / s->sg_cnt,
7720 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7721 ASC_PRT_NEXT();
7722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007723
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007724 /*
7725 * Display request queuing statistics.
7726 */
7727 len = asc_prt_line(cp, leftlen,
7728 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7729 HZ);
7730 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007732 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007733}
7734
7735/*
7736 * asc_prt_target_stats()
7737 *
7738 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7739 * cf. asc_prt_line().
7740 *
7741 * This is separated from asc_prt_board_stats because a full set
7742 * of targets will overflow ASC_PRTBUF_SIZE.
7743 *
7744 * Return the number of characters copied into 'cp'. No more than
7745 * 'cplen' characters will be copied to 'cp'.
7746 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007747static int
7748asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007749{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007750 int leftlen;
7751 int totlen;
7752 int len;
7753 struct asc_stats *s;
7754 ushort chip_scsi_id;
7755 asc_board_t *boardp;
7756 asc_queue_t *active;
7757 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007758
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007759 leftlen = cplen;
7760 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007762 boardp = ASC_BOARDP(shost);
7763 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007764
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007765 active = &ASC_BOARDP(shost)->active;
7766 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007767
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007768 if (ASC_NARROW_BOARD(boardp)) {
7769 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7770 } else {
7771 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007773
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007774 if ((chip_scsi_id == tgt_id) ||
7775 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7776 return 0;
7777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007778
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007779 do {
7780 if (active->q_tot_cnt[tgt_id] > 0
7781 || waiting->q_tot_cnt[tgt_id] > 0) {
7782 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
7783 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007784
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007785 len = asc_prt_line(cp, leftlen,
7786 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7787 active->q_cur_cnt[tgt_id],
7788 active->q_max_cnt[tgt_id],
7789 active->q_tot_cnt[tgt_id],
7790 active->q_min_tim[tgt_id],
7791 active->q_max_tim[tgt_id],
7792 (active->q_tot_cnt[tgt_id] ==
7793 0) ? 0 : (active->
7794 q_tot_tim[tgt_id] /
7795 active->
7796 q_tot_cnt[tgt_id]),
7797 (active->q_tot_cnt[tgt_id] ==
7798 0) ? 0 : ASC_TENTHS(active->
7799 q_tot_tim
7800 [tgt_id],
7801 active->
7802 q_tot_cnt
7803 [tgt_id]));
7804 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007805
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007806 len = asc_prt_line(cp, leftlen,
7807 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7808 waiting->q_cur_cnt[tgt_id],
7809 waiting->q_max_cnt[tgt_id],
7810 waiting->q_tot_cnt[tgt_id],
7811 waiting->q_min_tim[tgt_id],
7812 waiting->q_max_tim[tgt_id],
7813 (waiting->q_tot_cnt[tgt_id] ==
7814 0) ? 0 : (waiting->
7815 q_tot_tim[tgt_id] /
7816 waiting->
7817 q_tot_cnt[tgt_id]),
7818 (waiting->q_tot_cnt[tgt_id] ==
7819 0) ? 0 : ASC_TENTHS(waiting->
7820 q_tot_tim
7821 [tgt_id],
7822 waiting->
7823 q_tot_cnt
7824 [tgt_id]));
7825 ASC_PRT_NEXT();
7826 }
7827 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007829 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007830}
7831#endif /* CONFIG_PROC_FS */
7832#endif /* ADVANSYS_STATS */
7833
7834#ifdef ADVANSYS_DEBUG
7835/*
7836 * asc_prt_scsi_host()
7837 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007838static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007839{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007840 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007841
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007842 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007843
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007844 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7845 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7846 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007847
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007848 printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
7849 (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007851 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7852 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007854 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7855 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007857 if (ASC_NARROW_BOARD(boardp)) {
7858 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7859 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7860 } else {
7861 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7862 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007864}
7865
7866/*
7867 * asc_prt_scsi_cmnd()
7868 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007869static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007870{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007871 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007872
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007873 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7874 (ulong)s->device->host, (ulong)s->device, s->device->id,
7875 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007876
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007877 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007878
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007879 printk("sc_data_direction %u, resid %d\n",
7880 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007881
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007882 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007883
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007884 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7885 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007887 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007888
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007889 printk
7890 (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
7891 (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble,
7892 s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007893
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007894 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007895}
7896
7897/*
7898 * asc_prt_asc_dvc_var()
7899 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007900static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007901{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007902 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007903
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007904 printk
7905 (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
7906 h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007908 printk
7909 (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
7910 h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback,
7911 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007912
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007913 printk
7914 (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
7915 (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng,
7916 (unsigned)h->unit_not_ready, (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007917
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007918 printk
7919 (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
7920 (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor,
7921 (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007922
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007923 printk
7924 (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
7925 (unsigned)h->is_in_int, (unsigned)h->max_total_qng,
7926 (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007927
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007928 printk
7929 (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
7930 (unsigned)h->last_q_shortage, (unsigned)h->init_state,
7931 (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007933 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007934}
7935
7936/*
7937 * asc_prt_asc_dvc_cfg()
7938 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007939static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007940{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007941 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007942
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007943 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7944 h->can_tagged_qng, h->cmd_qng_enabled);
7945 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7946 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007948 printk
7949 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7950 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7951 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007952
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007953 printk
7954 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7955 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7956 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007957
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007958 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7959 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007960}
7961
7962/*
7963 * asc_prt_asc_scsi_q()
7964 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007965static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007966{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007967 ASC_SG_HEAD *sgp;
7968 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007969
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007970 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007971
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007972 printk
7973 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7974 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7975 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007976
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007977 printk
7978 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7979 (ulong)le32_to_cpu(q->q1.data_addr),
7980 (ulong)le32_to_cpu(q->q1.data_cnt),
7981 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007982
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007983 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
7984 (ulong)q->cdbptr, q->q2.cdb_len,
7985 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007986
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007987 if (q->sg_head) {
7988 sgp = q->sg_head;
7989 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
7990 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
7991 sgp->queue_cnt);
7992 for (i = 0; i < sgp->entry_cnt; i++) {
7993 printk(" [%u]: addr 0x%lx, bytes %lu\n",
7994 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
7995 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
7996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007997
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007999}
8000
8001/*
8002 * asc_prt_asc_qdone_info()
8003 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008004static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008005{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008006 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
8007 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
8008 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
8009 q->d2.tag_code);
8010 printk
8011 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
8012 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008013}
8014
8015/*
8016 * asc_prt_adv_dvc_var()
8017 *
8018 * Display an ADV_DVC_VAR structure.
8019 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008020static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008021{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008022 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008023
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008024 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
8025 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008027 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
8028 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
8029 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008030
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008031 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
8032 (unsigned)h->start_motor,
8033 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008034
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008035 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
8036 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
8037 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008038
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008039 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
8040 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008042 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
8043 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008044
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008045 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
8046 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008047}
8048
8049/*
8050 * asc_prt_adv_dvc_cfg()
8051 *
8052 * Display an ADV_DVC_CFG structure.
8053 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008054static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008055{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008056 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008057
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008058 printk(" disc_enable 0x%x, termination 0x%x\n",
8059 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008060
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008061 printk(" chip_version 0x%x, mcode_date 0x%x\n",
8062 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008063
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008064 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
8065 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008066
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008067 printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
8068 h->control_flag, h->pci_slot_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008069}
8070
8071/*
8072 * asc_prt_adv_scsi_req_q()
8073 *
8074 * Display an ADV_SCSI_REQ_Q structure.
8075 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008076static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008077{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008078 int sg_blk_cnt;
8079 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008081 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008083 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
8084 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008086 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
8087 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008088
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008089 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
8090 (ulong)le32_to_cpu(q->data_cnt),
8091 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008092
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008093 printk
8094 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
8095 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008096
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008097 printk(" sg_working_ix 0x%x, target_cmd %u\n",
8098 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008099
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008100 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
8101 (ulong)le32_to_cpu(q->scsiq_rptr),
8102 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008103
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008104 /* Display the request's ADV_SG_BLOCK structures. */
8105 if (q->sg_list_ptr != NULL) {
8106 sg_blk_cnt = 0;
8107 while (1) {
8108 /*
8109 * 'sg_ptr' is a physical address. Convert it to a virtual
8110 * address by indexing 'sg_blk_cnt' into the virtual address
8111 * array 'sg_list_ptr'.
8112 *
8113 * XXX - Assumes all SG physical blocks are virtually contiguous.
8114 */
8115 sg_ptr =
8116 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
8117 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
8118 if (sg_ptr->sg_ptr == 0) {
8119 break;
8120 }
8121 sg_blk_cnt++;
8122 }
8123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008124}
8125
8126/*
8127 * asc_prt_adv_sgblock()
8128 *
8129 * Display an ADV_SG_BLOCK structure.
8130 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008131static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008132{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008133 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008134
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008135 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
8136 (ulong)b, sgblockno);
8137 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
8138 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
8139 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
8140 if (b->sg_ptr != 0) {
8141 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
8142 }
8143 for (i = 0; i < b->sg_cnt; i++) {
8144 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
8145 i, (ulong)b->sg_list[i].sg_addr,
8146 (ulong)b->sg_list[i].sg_count);
8147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008148}
8149
8150/*
8151 * asc_prt_hex()
8152 *
8153 * Print hexadecimal output in 4 byte groupings 32 bytes
8154 * or 8 double-words per line.
8155 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008156static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008157{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008158 int i;
8159 int j;
8160 int k;
8161 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008162
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008163 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008164
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008165 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008167 /* Display a maximum of 8 double-words per line. */
8168 if ((k = (l - i) / 4) >= 8) {
8169 k = 8;
8170 m = 0;
8171 } else {
8172 m = (l - i) % 4;
8173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008174
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008175 for (j = 0; j < k; j++) {
8176 printk(" %2.2X%2.2X%2.2X%2.2X",
8177 (unsigned)s[i + (j * 4)],
8178 (unsigned)s[i + (j * 4) + 1],
8179 (unsigned)s[i + (j * 4) + 2],
8180 (unsigned)s[i + (j * 4) + 3]);
8181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008182
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008183 switch (m) {
8184 case 0:
8185 default:
8186 break;
8187 case 1:
8188 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
8189 break;
8190 case 2:
8191 printk(" %2.2X%2.2X",
8192 (unsigned)s[i + (j * 4)],
8193 (unsigned)s[i + (j * 4) + 1]);
8194 break;
8195 case 3:
8196 printk(" %2.2X%2.2X%2.2X",
8197 (unsigned)s[i + (j * 4) + 1],
8198 (unsigned)s[i + (j * 4) + 2],
8199 (unsigned)s[i + (j * 4) + 3]);
8200 break;
8201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008202
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008203 printk("\n");
8204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008205}
8206#endif /* ADVANSYS_DEBUG */
8207
8208/*
8209 * --- Asc Library Functions
8210 */
8211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008212static ushort __init AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008213{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008214 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008215
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008216 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
8217 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
8218 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008219}
8220
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008221static uchar __init AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008222{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008223 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008224
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008225 if (AscGetChipScsiID(iop_base) == new_host_id) {
8226 return (new_host_id);
8227 }
8228 cfg_lsw = AscGetChipCfgLsw(iop_base);
8229 cfg_lsw &= 0xF8FF;
8230 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
8231 AscSetChipCfgLsw(iop_base, cfg_lsw);
8232 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008233}
8234
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008235static uchar __init AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008236{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008237 uchar sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008238
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008239 AscSetBank(iop_base, 1);
8240 sc = inp(iop_base + IOP_REG_SC);
8241 AscSetBank(iop_base, 0);
8242 return (sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008243}
8244
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008245static uchar __init AscGetChipVersion(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008246{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008247 if ((bus_type & ASC_IS_EISA) != 0) {
8248 PortAddr eisa_iop;
8249 uchar revision;
8250 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
8251 (PortAddr) ASC_EISA_REV_IOP_MASK;
8252 revision = inp(eisa_iop);
8253 return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision));
8254 }
8255 return (AscGetChipVerNo(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008256}
8257
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008258static ushort __init AscGetChipBusType(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008259{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008260 ushort chip_ver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008261
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008262 chip_ver = AscGetChipVerNo(iop_base);
8263 if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
8264 && (chip_ver <= ASC_CHIP_MAX_VER_VL)
8265 ) {
8266 if (((iop_base & 0x0C30) == 0x0C30)
8267 || ((iop_base & 0x0C50) == 0x0C50)
8268 ) {
8269 return (ASC_IS_EISA);
8270 }
8271 return (ASC_IS_VL);
8272 }
8273 if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
8274 (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
8275 if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
8276 return (ASC_IS_ISAPNP);
8277 }
8278 return (ASC_IS_ISA);
8279 } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
8280 (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
8281 return (ASC_IS_PCI);
8282 }
8283 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008284}
8285
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008286static ASC_DCNT
8287AscLoadMicroCode(PortAddr iop_base,
8288 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008289{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008290 ASC_DCNT chksum;
8291 ushort mcode_word_size;
8292 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008293
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008294 /* Write the microcode buffer starting at LRAM address 0. */
8295 mcode_word_size = (ushort)(mcode_size >> 1);
8296 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
8297 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008298
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008299 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
8300 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
8301 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
8302 (ushort)ASC_CODE_SEC_BEG,
8303 (ushort)((mcode_size -
8304 s_addr - (ushort)
8305 ASC_CODE_SEC_BEG) /
8306 2));
8307 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
8308 (ulong)mcode_chksum);
8309 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
8310 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
8311 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008312}
8313
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008314static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008315{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008316 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008317
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008318 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
8319 iop_base, AscGetChipSignatureByte(iop_base));
8320 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
8321 ASC_DBG2(1,
8322 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
8323 iop_base, AscGetChipSignatureWord(iop_base));
8324 sig_word = AscGetChipSignatureWord(iop_base);
8325 if ((sig_word == (ushort)ASC_1000_ID0W) ||
8326 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
8327 return (1);
8328 }
8329 }
8330 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008331}
8332
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008333static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata = {
8334 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
8335 ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
Linus Torvalds1da177e2005-04-16 15:20:36 -07008336};
8337
8338#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008339static uchar _isa_pnp_inited __initdata = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008340
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008341static PortAddr __init AscSearchIOPortAddr(PortAddr iop_beg, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008342{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008343 if (bus_type & ASC_IS_VL) {
8344 while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
8345 if (AscGetChipVersion(iop_beg, bus_type) <=
8346 ASC_CHIP_MAX_VER_VL) {
8347 return (iop_beg);
8348 }
8349 }
8350 return (0);
8351 }
8352 if (bus_type & ASC_IS_ISA) {
8353 if (_isa_pnp_inited == 0) {
8354 AscSetISAPNPWaitForKey();
8355 _isa_pnp_inited++;
8356 }
8357 while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
8358 if ((AscGetChipVersion(iop_beg, bus_type) &
8359 ASC_CHIP_VER_ISA_BIT) != 0) {
8360 return (iop_beg);
8361 }
8362 }
8363 return (0);
8364 }
8365 if (bus_type & ASC_IS_EISA) {
8366 if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
8367 return (iop_beg);
8368 }
8369 return (0);
8370 }
8371 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008372}
8373
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008374static PortAddr __init AscSearchIOPortAddr11(PortAddr s_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008375{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008376 int i;
8377 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008378
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008379 for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
8380 if (_asc_def_iop_base[i] > s_addr) {
8381 break;
8382 }
8383 }
8384 for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
8385 iop_base = _asc_def_iop_base[i];
8386 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
8387 ASC_DBG1(1,
8388 "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
8389 iop_base);
8390 continue;
8391 }
8392 ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n",
8393 iop_base);
8394 release_region(iop_base, ASC_IOADR_GAP);
8395 if (AscFindSignature(iop_base)) {
8396 return (iop_base);
8397 }
8398 }
8399 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008400}
8401
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008402static void __init AscSetISAPNPWaitForKey(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008403{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008404 outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
8405 outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
8406 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008407}
8408#endif /* CONFIG_ISA */
8409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008410static void __init AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008411{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008412 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
8413 AscSetChipStatus(iop_base, 0);
8414 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008415}
8416
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008417static uchar __init AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008418{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008419 ushort cfg_lsw;
8420 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008421
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008422 if ((bus_type & ASC_IS_EISA) != 0) {
8423 cfg_lsw = AscGetEisaChipCfg(iop_base);
8424 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8425 if ((chip_irq == 13) || (chip_irq > 15)) {
8426 return (0);
8427 }
8428 return (chip_irq);
8429 }
8430 if ((bus_type & ASC_IS_VL) != 0) {
8431 cfg_lsw = AscGetChipCfgLsw(iop_base);
8432 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8433 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8434 return (0);
8435 }
8436 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8437 }
8438 cfg_lsw = AscGetChipCfgLsw(iop_base);
8439 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8440 if (chip_irq == 3)
8441 chip_irq += (uchar)2;
8442 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008443}
8444
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008445static uchar __init
8446AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008447{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008448 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008450 if ((bus_type & ASC_IS_VL) != 0) {
8451 if (irq_no != 0) {
8452 if ((irq_no < ASC_MIN_IRQ_NO)
8453 || (irq_no > ASC_MAX_IRQ_NO)) {
8454 irq_no = 0;
8455 } else {
8456 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8457 }
8458 }
8459 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8460 cfg_lsw |= (ushort)0x0010;
8461 AscSetChipCfgLsw(iop_base, cfg_lsw);
8462 AscToggleIRQAct(iop_base);
8463 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8464 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8465 AscSetChipCfgLsw(iop_base, cfg_lsw);
8466 AscToggleIRQAct(iop_base);
8467 return (AscGetChipIRQ(iop_base, bus_type));
8468 }
8469 if ((bus_type & (ASC_IS_ISA)) != 0) {
8470 if (irq_no == 15)
8471 irq_no -= (uchar)2;
8472 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8473 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8474 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8475 AscSetChipCfgLsw(iop_base, cfg_lsw);
8476 return (AscGetChipIRQ(iop_base, bus_type));
8477 }
8478 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008479}
8480
8481#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008482static void __init AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008483{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008484 if (dma_channel < 4) {
8485 outp(0x000B, (ushort)(0xC0 | dma_channel));
8486 outp(0x000A, dma_channel);
8487 } else if (dma_channel < 8) {
8488 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8489 outp(0x00D4, (ushort)(dma_channel - 4));
8490 }
8491 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008492}
8493#endif /* CONFIG_ISA */
8494
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008495static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008496{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008497 EXT_MSG ext_msg;
8498 EXT_MSG out_msg;
8499 ushort halt_q_addr;
8500 int sdtr_accept;
8501 ushort int_halt_code;
8502 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8503 ASC_SCSI_BIT_ID_TYPE target_id;
8504 PortAddr iop_base;
8505 uchar tag_code;
8506 uchar q_status;
8507 uchar halt_qp;
8508 uchar sdtr_data;
8509 uchar target_ix;
8510 uchar q_cntl, tid_no;
8511 uchar cur_dvc_qng;
8512 uchar asyn_sdtr;
8513 uchar scsi_status;
8514 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008515
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008516 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8517 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008518
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008519 iop_base = asc_dvc->iop_base;
8520 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008521
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008522 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8523 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8524 target_ix = AscReadLramByte(iop_base,
8525 (ushort)(halt_q_addr +
8526 (ushort)ASC_SCSIQ_B_TARGET_IX));
8527 q_cntl =
8528 AscReadLramByte(iop_base,
8529 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8530 tid_no = ASC_TIX_TO_TID(target_ix);
8531 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8532 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8533 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8534 } else {
8535 asyn_sdtr = 0;
8536 }
8537 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8538 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8539 AscSetChipSDTR(iop_base, 0, tid_no);
8540 boardp->sdtr_data[tid_no] = 0;
8541 }
8542 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8543 return (0);
8544 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8545 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8546 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8547 boardp->sdtr_data[tid_no] = asyn_sdtr;
8548 }
8549 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8550 return (0);
8551 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008553 AscMemWordCopyPtrFromLram(iop_base,
8554 ASCV_MSGIN_BEG,
8555 (uchar *)&ext_msg,
8556 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008557
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008558 if (ext_msg.msg_type == MS_EXTEND &&
8559 ext_msg.msg_req == MS_SDTR_CODE &&
8560 ext_msg.msg_len == MS_SDTR_LEN) {
8561 sdtr_accept = TRUE;
8562 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008563
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008564 sdtr_accept = FALSE;
8565 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8566 }
8567 if ((ext_msg.xfer_period <
8568 asc_dvc->sdtr_period_tbl[asc_dvc->
8569 host_init_sdtr_index])
8570 || (ext_msg.xfer_period >
8571 asc_dvc->sdtr_period_tbl[asc_dvc->
8572 max_sdtr_index])) {
8573 sdtr_accept = FALSE;
8574 ext_msg.xfer_period =
8575 asc_dvc->sdtr_period_tbl[asc_dvc->
8576 host_init_sdtr_index];
8577 }
8578 if (sdtr_accept) {
8579 sdtr_data =
8580 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8581 ext_msg.req_ack_offset);
8582 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008583
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008584 q_cntl |= QC_MSG_OUT;
8585 asc_dvc->init_sdtr &= ~target_id;
8586 asc_dvc->sdtr_done &= ~target_id;
8587 AscSetChipSDTR(iop_base, asyn_sdtr,
8588 tid_no);
8589 boardp->sdtr_data[tid_no] = asyn_sdtr;
8590 }
8591 }
8592 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008593
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008594 q_cntl &= ~QC_MSG_OUT;
8595 asc_dvc->init_sdtr &= ~target_id;
8596 asc_dvc->sdtr_done &= ~target_id;
8597 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8598 } else {
8599 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008600
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008601 q_cntl &= ~QC_MSG_OUT;
8602 asc_dvc->sdtr_done |= target_id;
8603 asc_dvc->init_sdtr |= target_id;
8604 asc_dvc->pci_fix_asyn_xfer &=
8605 ~target_id;
8606 sdtr_data =
8607 AscCalSDTRData(asc_dvc,
8608 ext_msg.xfer_period,
8609 ext_msg.
8610 req_ack_offset);
8611 AscSetChipSDTR(iop_base, sdtr_data,
8612 tid_no);
8613 boardp->sdtr_data[tid_no] = sdtr_data;
8614 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008615
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008616 q_cntl |= QC_MSG_OUT;
8617 AscMsgOutSDTR(asc_dvc,
8618 ext_msg.xfer_period,
8619 ext_msg.req_ack_offset);
8620 asc_dvc->pci_fix_asyn_xfer &=
8621 ~target_id;
8622 sdtr_data =
8623 AscCalSDTRData(asc_dvc,
8624 ext_msg.xfer_period,
8625 ext_msg.
8626 req_ack_offset);
8627 AscSetChipSDTR(iop_base, sdtr_data,
8628 tid_no);
8629 boardp->sdtr_data[tid_no] = sdtr_data;
8630 asc_dvc->sdtr_done |= target_id;
8631 asc_dvc->init_sdtr |= target_id;
8632 }
8633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008634
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008635 AscWriteLramByte(iop_base,
8636 (ushort)(halt_q_addr +
8637 (ushort)ASC_SCSIQ_B_CNTL),
8638 q_cntl);
8639 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8640 return (0);
8641 } else if (ext_msg.msg_type == MS_EXTEND &&
8642 ext_msg.msg_req == MS_WDTR_CODE &&
8643 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008644
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008645 ext_msg.wdtr_width = 0;
8646 AscMemWordCopyPtrToLram(iop_base,
8647 ASCV_MSGOUT_BEG,
8648 (uchar *)&ext_msg,
8649 sizeof(EXT_MSG) >> 1);
8650 q_cntl |= QC_MSG_OUT;
8651 AscWriteLramByte(iop_base,
8652 (ushort)(halt_q_addr +
8653 (ushort)ASC_SCSIQ_B_CNTL),
8654 q_cntl);
8655 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8656 return (0);
8657 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008658
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008659 ext_msg.msg_type = MESSAGE_REJECT;
8660 AscMemWordCopyPtrToLram(iop_base,
8661 ASCV_MSGOUT_BEG,
8662 (uchar *)&ext_msg,
8663 sizeof(EXT_MSG) >> 1);
8664 q_cntl |= QC_MSG_OUT;
8665 AscWriteLramByte(iop_base,
8666 (ushort)(halt_q_addr +
8667 (ushort)ASC_SCSIQ_B_CNTL),
8668 q_cntl);
8669 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8670 return (0);
8671 }
8672 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008673
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008674 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008676 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008677
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008678 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008679
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008680 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8681 q_cntl |= QC_MSG_OUT;
8682 AscMsgOutSDTR(asc_dvc,
8683 asc_dvc->
8684 sdtr_period_tbl[(sdtr_data >> 4) &
8685 (uchar)(asc_dvc->
8686 max_sdtr_index -
8687 1)],
8688 (uchar)(sdtr_data & (uchar)
8689 ASC_SYN_MAX_OFFSET));
8690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008691
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008692 AscWriteLramByte(iop_base,
8693 (ushort)(halt_q_addr +
8694 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008695
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008696 tag_code = AscReadLramByte(iop_base,
8697 (ushort)(halt_q_addr + (ushort)
8698 ASC_SCSIQ_B_TAG_CODE));
8699 tag_code &= 0xDC;
8700 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8701 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8702 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008703
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008704 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8705 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008706
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008707 }
8708 AscWriteLramByte(iop_base,
8709 (ushort)(halt_q_addr +
8710 (ushort)ASC_SCSIQ_B_TAG_CODE),
8711 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008712
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008713 q_status = AscReadLramByte(iop_base,
8714 (ushort)(halt_q_addr + (ushort)
8715 ASC_SCSIQ_B_STATUS));
8716 q_status |= (QS_READY | QS_BUSY);
8717 AscWriteLramByte(iop_base,
8718 (ushort)(halt_q_addr +
8719 (ushort)ASC_SCSIQ_B_STATUS),
8720 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008721
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008722 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8723 scsi_busy &= ~target_id;
8724 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008725
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008726 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8727 return (0);
8728 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008729
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008730 AscMemWordCopyPtrFromLram(iop_base,
8731 ASCV_MSGOUT_BEG,
8732 (uchar *)&out_msg,
8733 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008734
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008735 if ((out_msg.msg_type == MS_EXTEND) &&
8736 (out_msg.msg_len == MS_SDTR_LEN) &&
8737 (out_msg.msg_req == MS_SDTR_CODE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008738
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008739 asc_dvc->init_sdtr &= ~target_id;
8740 asc_dvc->sdtr_done &= ~target_id;
8741 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8742 boardp->sdtr_data[tid_no] = asyn_sdtr;
8743 }
8744 q_cntl &= ~QC_MSG_OUT;
8745 AscWriteLramByte(iop_base,
8746 (ushort)(halt_q_addr +
8747 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8748 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8749 return (0);
8750 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008752 scsi_status = AscReadLramByte(iop_base,
8753 (ushort)((ushort)halt_q_addr +
8754 (ushort)
8755 ASC_SCSIQ_SCSI_STATUS));
8756 cur_dvc_qng =
8757 AscReadLramByte(iop_base,
8758 (ushort)((ushort)ASC_QADR_BEG +
8759 (ushort)target_ix));
8760 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008762 scsi_busy = AscReadLramByte(iop_base,
8763 (ushort)ASCV_SCSIBUSY_B);
8764 scsi_busy |= target_id;
8765 AscWriteLramByte(iop_base,
8766 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8767 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008769 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8770 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8771 cur_dvc_qng -= 1;
8772 asc_dvc->max_dvc_qng[tid_no] =
8773 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008774
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008775 AscWriteLramByte(iop_base,
8776 (ushort)((ushort)
8777 ASCV_MAX_DVC_QNG_BEG
8778 + (ushort)
8779 tid_no),
8780 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008781
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008782 /*
8783 * Set the device queue depth to the number of
8784 * active requests when the QUEUE FULL condition
8785 * was encountered.
8786 */
8787 boardp->queue_full |= target_id;
8788 boardp->queue_full_cnt[tid_no] =
8789 cur_dvc_qng;
8790 }
8791 }
8792 }
8793 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8794 return (0);
8795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008796#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008797 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8798 uchar q_no;
8799 ushort q_addr;
8800 uchar sg_wk_q_no;
8801 uchar first_sg_wk_q_no;
8802 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8803 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8804 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8805 ushort sg_list_dwords;
8806 ushort sg_entry_cnt;
8807 uchar next_qp;
8808 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008810 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8811 if (q_no == ASC_QLINK_END) {
8812 return (0);
8813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008814
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008815 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008816
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008817 /*
8818 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8819 * structure pointer using a macro provided by the driver.
8820 * The ASC_SCSI_REQ pointer provides a pointer to the
8821 * host ASC_SG_HEAD structure.
8822 */
8823 /* Read request's SRB pointer. */
8824 scsiq = (ASC_SCSI_Q *)
8825 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8826 (ushort)
8827 (q_addr +
8828 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008829
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008830 /*
8831 * Get request's first and working SG queue.
8832 */
8833 sg_wk_q_no = AscReadLramByte(iop_base,
8834 (ushort)(q_addr +
8835 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008836
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008837 first_sg_wk_q_no = AscReadLramByte(iop_base,
8838 (ushort)(q_addr +
8839 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008840
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008841 /*
8842 * Reset request's working SG queue back to the
8843 * first SG queue.
8844 */
8845 AscWriteLramByte(iop_base,
8846 (ushort)(q_addr +
8847 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8848 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008850 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008851
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008852 /*
8853 * Set sg_entry_cnt to the number of SG elements
8854 * that will be completed on this interrupt.
8855 *
8856 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8857 * SG elements. The data_cnt and data_addr fields which
8858 * add 1 to the SG element capacity are not used when
8859 * restarting SG handling after a halt.
8860 */
8861 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8862 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008863
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008864 /*
8865 * Keep track of remaining number of SG elements that will
8866 * need to be handled on the next interrupt.
8867 */
8868 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8869 } else {
8870 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8871 scsiq->remain_sg_entry_cnt = 0;
8872 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008873
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008874 /*
8875 * Copy SG elements into the list of allocated SG queues.
8876 *
8877 * Last index completed is saved in scsiq->next_sg_index.
8878 */
8879 next_qp = first_sg_wk_q_no;
8880 q_addr = ASC_QNO_TO_QADDR(next_qp);
8881 scsi_sg_q.sg_head_qp = q_no;
8882 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8883 for (i = 0; i < sg_head->queue_cnt; i++) {
8884 scsi_sg_q.seq_no = i + 1;
8885 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8886 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8887 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8888 /*
8889 * After very first SG queue RISC FW uses next
8890 * SG queue first element then checks sg_list_cnt
8891 * against zero and then decrements, so set
8892 * sg_list_cnt 1 less than number of SG elements
8893 * in each SG queue.
8894 */
8895 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8896 scsi_sg_q.sg_cur_list_cnt =
8897 ASC_SG_LIST_PER_Q - 1;
8898 } else {
8899 /*
8900 * This is the last SG queue in the list of
8901 * allocated SG queues. If there are more
8902 * SG elements than will fit in the allocated
8903 * queues, then set the QCSG_SG_XFER_MORE flag.
8904 */
8905 if (scsiq->remain_sg_entry_cnt != 0) {
8906 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8907 } else {
8908 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8909 }
8910 /* equals sg_entry_cnt * 2 */
8911 sg_list_dwords = sg_entry_cnt << 1;
8912 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8913 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8914 sg_entry_cnt = 0;
8915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008916
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008917 scsi_sg_q.q_no = next_qp;
8918 AscMemWordCopyPtrToLram(iop_base,
8919 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8920 (uchar *)&scsi_sg_q,
8921 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008922
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008923 AscMemDWordCopyPtrToLram(iop_base,
8924 q_addr + ASC_SGQ_LIST_BEG,
8925 (uchar *)&sg_head->
8926 sg_list[scsiq->next_sg_index],
8927 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008929 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008930
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008931 /*
8932 * If the just completed SG queue contained the
8933 * last SG element, then no more SG queues need
8934 * to be written.
8935 */
8936 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8937 break;
8938 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008940 next_qp = AscReadLramByte(iop_base,
8941 (ushort)(q_addr +
8942 ASC_SCSIQ_B_FWD));
8943 q_addr = ASC_QNO_TO_QADDR(next_qp);
8944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008945
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008946 /*
8947 * Clear the halt condition so the RISC will be restarted
8948 * after the return.
8949 */
8950 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8951 return (0);
8952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008953#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008954 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008955}
8956
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008957static uchar
8958_AscCopyLramScsiDoneQ(PortAddr iop_base,
8959 ushort q_addr,
8960 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008961{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008962 ushort _val;
8963 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008964
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008965 DvcGetQinfo(iop_base,
8966 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8967 (uchar *)scsiq,
8968 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008969
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008970 _val = AscReadLramWord(iop_base,
8971 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8972 scsiq->q_status = (uchar)_val;
8973 scsiq->q_no = (uchar)(_val >> 8);
8974 _val = AscReadLramWord(iop_base,
8975 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8976 scsiq->cntl = (uchar)_val;
8977 sg_queue_cnt = (uchar)(_val >> 8);
8978 _val = AscReadLramWord(iop_base,
8979 (ushort)(q_addr +
8980 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8981 scsiq->sense_len = (uchar)_val;
8982 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008984 /*
8985 * Read high word of remain bytes from alternate location.
8986 */
8987 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
8988 (ushort)(q_addr +
8989 (ushort)
8990 ASC_SCSIQ_W_ALT_DC1)))
8991 << 16);
8992 /*
8993 * Read low word of remain bytes from original location.
8994 */
8995 scsiq->remain_bytes += AscReadLramWord(iop_base,
8996 (ushort)(q_addr + (ushort)
8997 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008998
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008999 scsiq->remain_bytes &= max_dma_count;
9000 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009001}
9002
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009003static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009004{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009005 uchar next_qp;
9006 uchar n_q_used;
9007 uchar sg_list_qp;
9008 uchar sg_queue_cnt;
9009 uchar q_cnt;
9010 uchar done_q_tail;
9011 uchar tid_no;
9012 ASC_SCSI_BIT_ID_TYPE scsi_busy;
9013 ASC_SCSI_BIT_ID_TYPE target_id;
9014 PortAddr iop_base;
9015 ushort q_addr;
9016 ushort sg_q_addr;
9017 uchar cur_target_qng;
9018 ASC_QDONE_INFO scsiq_buf;
9019 ASC_QDONE_INFO *scsiq;
9020 int false_overrun;
9021 ASC_ISR_CALLBACK asc_isr_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009022
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009023 iop_base = asc_dvc->iop_base;
9024 asc_isr_callback = asc_dvc->isr_callback;
9025 n_q_used = 1;
9026 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
9027 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
9028 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
9029 next_qp = AscReadLramByte(iop_base,
9030 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
9031 if (next_qp != ASC_QLINK_END) {
9032 AscPutVarDoneQTail(iop_base, next_qp);
9033 q_addr = ASC_QNO_TO_QADDR(next_qp);
9034 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
9035 asc_dvc->max_dma_count);
9036 AscWriteLramByte(iop_base,
9037 (ushort)(q_addr +
9038 (ushort)ASC_SCSIQ_B_STATUS),
9039 (uchar)(scsiq->
9040 q_status & (uchar)~(QS_READY |
9041 QS_ABORTED)));
9042 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
9043 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
9044 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
9045 sg_q_addr = q_addr;
9046 sg_list_qp = next_qp;
9047 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
9048 sg_list_qp = AscReadLramByte(iop_base,
9049 (ushort)(sg_q_addr
9050 + (ushort)
9051 ASC_SCSIQ_B_FWD));
9052 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
9053 if (sg_list_qp == ASC_QLINK_END) {
9054 AscSetLibErrorCode(asc_dvc,
9055 ASCQ_ERR_SG_Q_LINKS);
9056 scsiq->d3.done_stat = QD_WITH_ERROR;
9057 scsiq->d3.host_stat =
9058 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
9059 goto FATAL_ERR_QDONE;
9060 }
9061 AscWriteLramByte(iop_base,
9062 (ushort)(sg_q_addr + (ushort)
9063 ASC_SCSIQ_B_STATUS),
9064 QS_FREE);
9065 }
9066 n_q_used = sg_queue_cnt + 1;
9067 AscPutVarDoneQTail(iop_base, sg_list_qp);
9068 }
9069 if (asc_dvc->queue_full_or_busy & target_id) {
9070 cur_target_qng = AscReadLramByte(iop_base,
9071 (ushort)((ushort)
9072 ASC_QADR_BEG
9073 + (ushort)
9074 scsiq->d2.
9075 target_ix));
9076 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
9077 scsi_busy = AscReadLramByte(iop_base, (ushort)
9078 ASCV_SCSIBUSY_B);
9079 scsi_busy &= ~target_id;
9080 AscWriteLramByte(iop_base,
9081 (ushort)ASCV_SCSIBUSY_B,
9082 scsi_busy);
9083 asc_dvc->queue_full_or_busy &= ~target_id;
9084 }
9085 }
9086 if (asc_dvc->cur_total_qng >= n_q_used) {
9087 asc_dvc->cur_total_qng -= n_q_used;
9088 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
9089 asc_dvc->cur_dvc_qng[tid_no]--;
9090 }
9091 } else {
9092 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
9093 scsiq->d3.done_stat = QD_WITH_ERROR;
9094 goto FATAL_ERR_QDONE;
9095 }
9096 if ((scsiq->d2.srb_ptr == 0UL) ||
9097 ((scsiq->q_status & QS_ABORTED) != 0)) {
9098 return (0x11);
9099 } else if (scsiq->q_status == QS_DONE) {
9100 false_overrun = FALSE;
9101 if (scsiq->extra_bytes != 0) {
9102 scsiq->remain_bytes +=
9103 (ADV_DCNT)scsiq->extra_bytes;
9104 }
9105 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
9106 if (scsiq->d3.host_stat ==
9107 QHSTA_M_DATA_OVER_RUN) {
9108 if ((scsiq->
9109 cntl & (QC_DATA_IN | QC_DATA_OUT))
9110 == 0) {
9111 scsiq->d3.done_stat =
9112 QD_NO_ERROR;
9113 scsiq->d3.host_stat =
9114 QHSTA_NO_ERROR;
9115 } else if (false_overrun) {
9116 scsiq->d3.done_stat =
9117 QD_NO_ERROR;
9118 scsiq->d3.host_stat =
9119 QHSTA_NO_ERROR;
9120 }
9121 } else if (scsiq->d3.host_stat ==
9122 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
9123 AscStopChip(iop_base);
9124 AscSetChipControl(iop_base,
9125 (uchar)(CC_SCSI_RESET
9126 | CC_HALT));
9127 DvcDelayNanoSecond(asc_dvc, 60000);
9128 AscSetChipControl(iop_base, CC_HALT);
9129 AscSetChipStatus(iop_base,
9130 CIW_CLR_SCSI_RESET_INT);
9131 AscSetChipStatus(iop_base, 0);
9132 AscSetChipControl(iop_base, 0);
9133 }
9134 }
9135 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
9136 (*asc_isr_callback) (asc_dvc, scsiq);
9137 } else {
9138 if ((AscReadLramByte(iop_base,
9139 (ushort)(q_addr + (ushort)
9140 ASC_SCSIQ_CDB_BEG))
9141 == START_STOP)) {
9142 asc_dvc->unit_not_ready &= ~target_id;
9143 if (scsiq->d3.done_stat != QD_NO_ERROR) {
9144 asc_dvc->start_motor &=
9145 ~target_id;
9146 }
9147 }
9148 }
9149 return (1);
9150 } else {
9151 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
9152 FATAL_ERR_QDONE:
9153 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
9154 (*asc_isr_callback) (asc_dvc, scsiq);
9155 }
9156 return (0x80);
9157 }
9158 }
9159 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009160}
9161
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009162static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009163{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009164 ASC_CS_TYPE chipstat;
9165 PortAddr iop_base;
9166 ushort saved_ram_addr;
9167 uchar ctrl_reg;
9168 uchar saved_ctrl_reg;
9169 int int_pending;
9170 int status;
9171 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009172
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009173 iop_base = asc_dvc->iop_base;
9174 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009175
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009176 if (AscIsIntPending(iop_base) == 0) {
9177 return int_pending;
9178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009179
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009180 if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
9181 || (asc_dvc->isr_callback == 0)
9182 ) {
9183 return (ERR);
9184 }
9185 if (asc_dvc->in_critical_cnt != 0) {
9186 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
9187 return (ERR);
9188 }
9189 if (asc_dvc->is_in_int) {
9190 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
9191 return (ERR);
9192 }
9193 asc_dvc->is_in_int = TRUE;
9194 ctrl_reg = AscGetChipControl(iop_base);
9195 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
9196 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
9197 chipstat = AscGetChipStatus(iop_base);
9198 if (chipstat & CSW_SCSI_RESET_LATCH) {
9199 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
9200 int i = 10;
9201 int_pending = TRUE;
9202 asc_dvc->sdtr_done = 0;
9203 saved_ctrl_reg &= (uchar)(~CC_HALT);
9204 while ((AscGetChipStatus(iop_base) &
9205 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
9206 DvcSleepMilliSecond(100);
9207 }
9208 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
9209 AscSetChipControl(iop_base, CC_HALT);
9210 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
9211 AscSetChipStatus(iop_base, 0);
9212 chipstat = AscGetChipStatus(iop_base);
9213 }
9214 }
9215 saved_ram_addr = AscGetChipLramAddr(iop_base);
9216 host_flag = AscReadLramByte(iop_base,
9217 ASCV_HOST_FLAG_B) &
9218 (uchar)(~ASC_HOST_FLAG_IN_ISR);
9219 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
9220 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
9221 if ((chipstat & CSW_INT_PENDING)
9222 || (int_pending)
9223 ) {
9224 AscAckInterrupt(iop_base);
9225 int_pending = TRUE;
9226 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
9227 if (AscIsrChipHalted(asc_dvc) == ERR) {
9228 goto ISR_REPORT_QDONE_FATAL_ERROR;
9229 } else {
9230 saved_ctrl_reg &= (uchar)(~CC_HALT);
9231 }
9232 } else {
9233 ISR_REPORT_QDONE_FATAL_ERROR:
9234 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
9235 while (((status =
9236 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
9237 }
9238 } else {
9239 do {
9240 if ((status =
9241 AscIsrQDone(asc_dvc)) == 1) {
9242 break;
9243 }
9244 } while (status == 0x11);
9245 }
9246 if ((status & 0x80) != 0)
9247 int_pending = ERR;
9248 }
9249 }
9250 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
9251 AscSetChipLramAddr(iop_base, saved_ram_addr);
9252 AscSetChipControl(iop_base, saved_ctrl_reg);
9253 asc_dvc->is_in_int = FALSE;
9254 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009255}
9256
9257/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009258static uchar _asc_mcode_buf[] = {
9259 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9260 0x00, 0x00, 0x00, 0x00,
9261 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
9262 0x00, 0x00, 0x00, 0x00,
9263 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9264 0x00, 0x00, 0x00, 0x00,
9265 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9266 0x00, 0x00, 0x00, 0x00,
9267 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
9268 0x00, 0xFF, 0x00, 0x00,
9269 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
9270 0x00, 0x00, 0x00, 0x00,
9271 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
9272 0x00, 0x00, 0x00, 0x00,
9273 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
9274 0x00, 0x00, 0x00, 0x00,
9275 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
9276 0x03, 0x23, 0x36, 0x40,
9277 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
9278 0xC2, 0x00, 0x92, 0x80,
9279 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
9280 0xB6, 0x00, 0x92, 0x80,
9281 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
9282 0x92, 0x80, 0x80, 0x62,
9283 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
9284 0xCD, 0x04, 0x4D, 0x00,
9285 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
9286 0xE6, 0x84, 0xD2, 0xC1,
9287 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
9288 0xC6, 0x81, 0xC2, 0x88,
9289 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
9290 0x84, 0x97, 0x07, 0xA6,
9291 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
9292 0xC2, 0x88, 0xCE, 0x00,
9293 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
9294 0x80, 0x63, 0x07, 0xA6,
9295 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
9296 0x34, 0x01, 0x00, 0x33,
9297 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
9298 0x68, 0x98, 0x4D, 0x04,
9299 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
9300 0xF8, 0x88, 0xFB, 0x23,
9301 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
9302 0x00, 0x33, 0x0A, 0x00,
9303 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
9304 0xC2, 0x88, 0xCD, 0x04,
9305 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
9306 0x06, 0xAB, 0x82, 0x01,
9307 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
9308 0x3C, 0x01, 0x00, 0x05,
9309 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
9310 0x15, 0x23, 0xA1, 0x01,
9311 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
9312 0x06, 0x61, 0x00, 0xA0,
9313 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
9314 0xC2, 0x88, 0x06, 0x23,
9315 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
9316 0x57, 0x60, 0x00, 0xA0,
9317 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
9318 0x4B, 0x00, 0x06, 0x61,
9319 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
9320 0x4F, 0x00, 0x84, 0x97,
9321 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
9322 0x48, 0x04, 0x84, 0x80,
9323 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
9324 0x81, 0x73, 0x06, 0x29,
9325 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
9326 0x04, 0x98, 0xF0, 0x80,
9327 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
9328 0x34, 0x02, 0x03, 0xA6,
9329 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
9330 0x46, 0x82, 0xFE, 0x95,
9331 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
9332 0x07, 0xA6, 0x5A, 0x02,
9333 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
9334 0x48, 0x82, 0x60, 0x96,
9335 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
9336 0x04, 0x01, 0x0C, 0xDC,
9337 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
9338 0x6F, 0x00, 0xA5, 0x01,
9339 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
9340 0x02, 0xA6, 0xAA, 0x02,
9341 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
9342 0x01, 0xA6, 0xB4, 0x02,
9343 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
9344 0x80, 0x63, 0x00, 0x43,
9345 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
9346 0x04, 0x61, 0x84, 0x01,
9347 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
9348 0x00, 0x00, 0xEA, 0x82,
9349 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
9350 0x00, 0x33, 0x1F, 0x00,
9351 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
9352 0xB6, 0x2D, 0x01, 0xA6,
9353 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
9354 0x10, 0x03, 0x03, 0xA6,
9355 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
9356 0x7C, 0x95, 0xEE, 0x82,
9357 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
9358 0x04, 0x01, 0x2D, 0xC8,
9359 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
9360 0x05, 0x05, 0x86, 0x98,
9361 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
9362 0x3C, 0x04, 0x06, 0xA6,
9363 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
9364 0x7C, 0x95, 0x32, 0x83,
9365 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
9366 0xEB, 0x04, 0x00, 0x33,
9367 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
9368 0xFF, 0xA2, 0x7A, 0x03,
9369 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
9370 0x00, 0xA2, 0x9A, 0x03,
9371 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
9372 0x01, 0xA6, 0x96, 0x03,
9373 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
9374 0xA4, 0x03, 0x00, 0xA6,
9375 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
9376 0x07, 0xA6, 0xB2, 0x03,
9377 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
9378 0xA8, 0x98, 0x80, 0x42,
9379 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
9380 0xC0, 0x83, 0x00, 0x33,
9381 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
9382 0xA0, 0x01, 0x12, 0x23,
9383 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
9384 0x80, 0x67, 0x05, 0x23,
9385 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
9386 0x06, 0xA6, 0x0A, 0x04,
9387 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
9388 0xF4, 0x83, 0x20, 0x84,
9389 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
9390 0x83, 0x03, 0x80, 0x63,
9391 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
9392 0x38, 0x04, 0x00, 0x33,
9393 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
9394 0x1D, 0x01, 0x06, 0xCC,
9395 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
9396 0xA2, 0x0D, 0x80, 0x63,
9397 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
9398 0x80, 0x63, 0xA3, 0x01,
9399 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
9400 0x76, 0x04, 0xE0, 0x00,
9401 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
9402 0x00, 0x33, 0x1E, 0x00,
9403 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
9404 0x08, 0x23, 0x22, 0xA3,
9405 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
9406 0xC4, 0x04, 0x42, 0x23,
9407 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
9408 0xF8, 0x88, 0x04, 0x98,
9409 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
9410 0x81, 0x62, 0xE8, 0x81,
9411 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
9412 0x00, 0x33, 0x00, 0x81,
9413 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
9414 0xF8, 0x88, 0x04, 0x23,
9415 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
9416 0xF4, 0x04, 0x00, 0x33,
9417 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9418 0x04, 0x23, 0xA0, 0x01,
9419 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9420 0x00, 0xA3, 0x22, 0x05,
9421 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9422 0x46, 0x97, 0xCD, 0x04,
9423 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9424 0x82, 0x01, 0x34, 0x85,
9425 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9426 0x1D, 0x01, 0x04, 0xD6,
9427 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9428 0x49, 0x00, 0x81, 0x01,
9429 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9430 0x49, 0x04, 0x80, 0x01,
9431 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9432 0x01, 0x23, 0xEA, 0x00,
9433 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9434 0x07, 0xA4, 0xF8, 0x05,
9435 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9436 0xC2, 0x88, 0x04, 0xA0,
9437 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9438 0x00, 0xA2, 0xA4, 0x05,
9439 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9440 0x62, 0x97, 0x04, 0x85,
9441 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9442 0xF4, 0x85, 0x03, 0xA0,
9443 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9444 0xCC, 0x86, 0x07, 0xA0,
9445 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9446 0x80, 0x67, 0x80, 0x63,
9447 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9448 0xF8, 0x88, 0x07, 0x23,
9449 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9450 0x00, 0x63, 0x4A, 0x00,
9451 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9452 0x07, 0x41, 0x83, 0x03,
9453 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9454 0x1D, 0x01, 0x01, 0xD6,
9455 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9456 0x07, 0xA6, 0x7C, 0x05,
9457 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9458 0x52, 0x00, 0x06, 0x61,
9459 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9460 0x00, 0x63, 0x1D, 0x01,
9461 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9462 0x07, 0x41, 0x00, 0x63,
9463 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9464 0xDF, 0x00, 0x06, 0xA6,
9465 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9466 0x00, 0x40, 0xC0, 0x20,
9467 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9468 0x06, 0xA6, 0x94, 0x06,
9469 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9470 0x40, 0x0E, 0x80, 0x63,
9471 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9472 0x80, 0x63, 0x00, 0x43,
9473 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9474 0x80, 0x67, 0x40, 0x0E,
9475 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9476 0x07, 0xA6, 0xD6, 0x06,
9477 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9478 0x0A, 0x2B, 0x07, 0xA6,
9479 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9480 0xF4, 0x06, 0xC0, 0x0E,
9481 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9482 0x81, 0x62, 0x04, 0x01,
9483 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9484 0x8C, 0x06, 0x00, 0x33,
9485 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9486 0x80, 0x63, 0x06, 0xA6,
9487 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9488 0x00, 0x00, 0x80, 0x67,
9489 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9490 0xBF, 0x23, 0x04, 0x61,
9491 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9492 0x00, 0x01, 0xF2, 0x00,
9493 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9494 0x80, 0x05, 0x81, 0x05,
9495 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9496 0x70, 0x00, 0x81, 0x01,
9497 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9498 0x70, 0x00, 0x80, 0x01,
9499 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9500 0xF1, 0x00, 0x70, 0x00,
9501 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9502 0x71, 0x04, 0x70, 0x00,
9503 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9504 0xA3, 0x01, 0xA2, 0x01,
9505 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9506 0xC4, 0x07, 0x00, 0x33,
9507 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9508 0x48, 0x00, 0xB0, 0x01,
9509 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9510 0x00, 0xA2, 0xE4, 0x07,
9511 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9512 0x05, 0x05, 0x00, 0x63,
9513 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9514 0x76, 0x08, 0x80, 0x02,
9515 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9516 0x00, 0x02, 0x00, 0xA0,
9517 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9518 0x00, 0x63, 0xF3, 0x04,
9519 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9520 0x00, 0xA2, 0x44, 0x08,
9521 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9522 0x24, 0x08, 0x04, 0x98,
9523 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9524 0x5A, 0x88, 0x02, 0x01,
9525 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9526 0x00, 0xA3, 0x64, 0x08,
9527 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9528 0x06, 0xA6, 0x76, 0x08,
9529 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9530 0x00, 0x63, 0x38, 0x2B,
9531 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9532 0x05, 0x05, 0xB2, 0x09,
9533 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9534 0x80, 0x32, 0x80, 0x36,
9535 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9536 0x40, 0x36, 0x40, 0x3A,
9537 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9538 0x5D, 0x00, 0xFE, 0xC3,
9539 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9540 0xFF, 0xFD, 0x80, 0x73,
9541 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9542 0xA1, 0x23, 0xA1, 0x01,
9543 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9544 0x80, 0x00, 0x03, 0xC2,
9545 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9546 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009547};
9548
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009549static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9550static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009551
9552#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009553static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9554 INQUIRY,
9555 REQUEST_SENSE,
9556 READ_CAPACITY,
9557 READ_TOC,
9558 MODE_SELECT,
9559 MODE_SENSE,
9560 MODE_SELECT_10,
9561 MODE_SENSE_10,
9562 0xFF,
9563 0xFF,
9564 0xFF,
9565 0xFF,
9566 0xFF,
9567 0xFF,
9568 0xFF,
9569 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009570};
9571
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009572static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009573{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009574 PortAddr iop_base;
9575 ulong last_int_level;
9576 int sta;
9577 int n_q_required;
9578 int disable_syn_offset_one_fix;
9579 int i;
9580 ASC_PADDR addr;
9581 ASC_EXE_CALLBACK asc_exe_callback;
9582 ushort sg_entry_cnt = 0;
9583 ushort sg_entry_cnt_minus_one = 0;
9584 uchar target_ix;
9585 uchar tid_no;
9586 uchar sdtr_data;
9587 uchar extra_bytes;
9588 uchar scsi_cmd;
9589 uchar disable_cmd;
9590 ASC_SG_HEAD *sg_head;
9591 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009592
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009593 iop_base = asc_dvc->iop_base;
9594 sg_head = scsiq->sg_head;
9595 asc_exe_callback = asc_dvc->exe_callback;
9596 if (asc_dvc->err_code != 0)
9597 return (ERR);
9598 if (scsiq == (ASC_SCSI_Q *)0L) {
9599 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9600 return (ERR);
9601 }
9602 scsiq->q1.q_no = 0;
9603 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9604 scsiq->q1.extra_bytes = 0;
9605 }
9606 sta = 0;
9607 target_ix = scsiq->q2.target_ix;
9608 tid_no = ASC_TIX_TO_TID(target_ix);
9609 n_q_required = 1;
9610 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9611 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9612 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9613 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9614 AscMsgOutSDTR(asc_dvc,
9615 asc_dvc->
9616 sdtr_period_tbl[(sdtr_data >> 4) &
9617 (uchar)(asc_dvc->
9618 max_sdtr_index -
9619 1)],
9620 (uchar)(sdtr_data & (uchar)
9621 ASC_SYN_MAX_OFFSET));
9622 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9623 }
9624 }
9625 last_int_level = DvcEnterCritical();
9626 if (asc_dvc->in_critical_cnt != 0) {
9627 DvcLeaveCritical(last_int_level);
9628 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9629 return (ERR);
9630 }
9631 asc_dvc->in_critical_cnt++;
9632 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9633 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9634 asc_dvc->in_critical_cnt--;
9635 DvcLeaveCritical(last_int_level);
9636 return (ERR);
9637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009638#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009639 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9640 asc_dvc->in_critical_cnt--;
9641 DvcLeaveCritical(last_int_level);
9642 return (ERR);
9643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009644#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009645 if (sg_entry_cnt == 1) {
9646 scsiq->q1.data_addr =
9647 (ADV_PADDR)sg_head->sg_list[0].addr;
9648 scsiq->q1.data_cnt =
9649 (ADV_DCNT)sg_head->sg_list[0].bytes;
9650 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9651 }
9652 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9653 }
9654 scsi_cmd = scsiq->cdbptr[0];
9655 disable_syn_offset_one_fix = FALSE;
9656 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9657 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9658 if (scsiq->q1.cntl & QC_SG_HEAD) {
9659 data_cnt = 0;
9660 for (i = 0; i < sg_entry_cnt; i++) {
9661 data_cnt +=
9662 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9663 bytes);
9664 }
9665 } else {
9666 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9667 }
9668 if (data_cnt != 0UL) {
9669 if (data_cnt < 512UL) {
9670 disable_syn_offset_one_fix = TRUE;
9671 } else {
9672 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9673 i++) {
9674 disable_cmd =
9675 _syn_offset_one_disable_cmd[i];
9676 if (disable_cmd == 0xFF) {
9677 break;
9678 }
9679 if (scsi_cmd == disable_cmd) {
9680 disable_syn_offset_one_fix =
9681 TRUE;
9682 break;
9683 }
9684 }
9685 }
9686 }
9687 }
9688 if (disable_syn_offset_one_fix) {
9689 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9690 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9691 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9692 } else {
9693 scsiq->q2.tag_code &= 0x27;
9694 }
9695 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9696 if (asc_dvc->bug_fix_cntl) {
9697 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9698 if ((scsi_cmd == READ_6) ||
9699 (scsi_cmd == READ_10)) {
9700 addr =
9701 (ADV_PADDR)le32_to_cpu(sg_head->
9702 sg_list
9703 [sg_entry_cnt_minus_one].
9704 addr) +
9705 (ADV_DCNT)le32_to_cpu(sg_head->
9706 sg_list
9707 [sg_entry_cnt_minus_one].
9708 bytes);
9709 extra_bytes =
9710 (uchar)((ushort)addr & 0x0003);
9711 if ((extra_bytes != 0)
9712 &&
9713 ((scsiq->q2.
9714 tag_code &
9715 ASC_TAG_FLAG_EXTRA_BYTES)
9716 == 0)) {
9717 scsiq->q2.tag_code |=
9718 ASC_TAG_FLAG_EXTRA_BYTES;
9719 scsiq->q1.extra_bytes =
9720 extra_bytes;
9721 data_cnt =
9722 le32_to_cpu(sg_head->
9723 sg_list
9724 [sg_entry_cnt_minus_one].
9725 bytes);
9726 data_cnt -=
9727 (ASC_DCNT) extra_bytes;
9728 sg_head->
9729 sg_list
9730 [sg_entry_cnt_minus_one].
9731 bytes =
9732 cpu_to_le32(data_cnt);
9733 }
9734 }
9735 }
9736 }
9737 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009738#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009739 /*
9740 * Set the sg_entry_cnt to the maximum possible. The rest of
9741 * the SG elements will be copied when the RISC completes the
9742 * SG elements that fit and halts.
9743 */
9744 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9745 sg_entry_cnt = ASC_MAX_SG_LIST;
9746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009747#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009748 n_q_required = AscSgListToQueue(sg_entry_cnt);
9749 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9750 (uint) n_q_required)
9751 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9752 if ((sta =
9753 AscSendScsiQueue(asc_dvc, scsiq,
9754 n_q_required)) == 1) {
9755 asc_dvc->in_critical_cnt--;
9756 if (asc_exe_callback != 0) {
9757 (*asc_exe_callback) (asc_dvc, scsiq);
9758 }
9759 DvcLeaveCritical(last_int_level);
9760 return (sta);
9761 }
9762 }
9763 } else {
9764 if (asc_dvc->bug_fix_cntl) {
9765 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9766 if ((scsi_cmd == READ_6) ||
9767 (scsi_cmd == READ_10)) {
9768 addr =
9769 le32_to_cpu(scsiq->q1.data_addr) +
9770 le32_to_cpu(scsiq->q1.data_cnt);
9771 extra_bytes =
9772 (uchar)((ushort)addr & 0x0003);
9773 if ((extra_bytes != 0)
9774 &&
9775 ((scsiq->q2.
9776 tag_code &
9777 ASC_TAG_FLAG_EXTRA_BYTES)
9778 == 0)) {
9779 data_cnt =
9780 le32_to_cpu(scsiq->q1.
9781 data_cnt);
9782 if (((ushort)data_cnt & 0x01FF)
9783 == 0) {
9784 scsiq->q2.tag_code |=
9785 ASC_TAG_FLAG_EXTRA_BYTES;
9786 data_cnt -= (ASC_DCNT)
9787 extra_bytes;
9788 scsiq->q1.data_cnt =
9789 cpu_to_le32
9790 (data_cnt);
9791 scsiq->q1.extra_bytes =
9792 extra_bytes;
9793 }
9794 }
9795 }
9796 }
9797 }
9798 n_q_required = 1;
9799 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9800 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9801 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9802 n_q_required)) == 1) {
9803 asc_dvc->in_critical_cnt--;
9804 if (asc_exe_callback != 0) {
9805 (*asc_exe_callback) (asc_dvc, scsiq);
9806 }
9807 DvcLeaveCritical(last_int_level);
9808 return (sta);
9809 }
9810 }
9811 }
9812 asc_dvc->in_critical_cnt--;
9813 DvcLeaveCritical(last_int_level);
9814 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009815}
9816
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009817static int
9818AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009819{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009820 PortAddr iop_base;
9821 uchar free_q_head;
9822 uchar next_qp;
9823 uchar tid_no;
9824 uchar target_ix;
9825 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009826
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009827 iop_base = asc_dvc->iop_base;
9828 target_ix = scsiq->q2.target_ix;
9829 tid_no = ASC_TIX_TO_TID(target_ix);
9830 sta = 0;
9831 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9832 if (n_q_required > 1) {
9833 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9834 free_q_head, (uchar)
9835 (n_q_required)))
9836 != (uchar)ASC_QLINK_END) {
9837 asc_dvc->last_q_shortage = 0;
9838 scsiq->sg_head->queue_cnt = n_q_required - 1;
9839 scsiq->q1.q_no = free_q_head;
9840 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9841 free_q_head)) == 1) {
9842 AscPutVarFreeQHead(iop_base, next_qp);
9843 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9844 asc_dvc->cur_dvc_qng[tid_no]++;
9845 }
9846 return (sta);
9847 }
9848 } else if (n_q_required == 1) {
9849 if ((next_qp = AscAllocFreeQueue(iop_base,
9850 free_q_head)) !=
9851 ASC_QLINK_END) {
9852 scsiq->q1.q_no = free_q_head;
9853 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9854 free_q_head)) == 1) {
9855 AscPutVarFreeQHead(iop_base, next_qp);
9856 asc_dvc->cur_total_qng++;
9857 asc_dvc->cur_dvc_qng[tid_no]++;
9858 }
9859 return (sta);
9860 }
9861 }
9862 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009863}
9864
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009865static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009866{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009867 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009868
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009869 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9870 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9871 n_sg_list_qs++;
9872 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009873}
9874
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009875static uint
9876AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009877{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009878 uint cur_used_qs;
9879 uint cur_free_qs;
9880 ASC_SCSI_BIT_ID_TYPE target_id;
9881 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009882
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009883 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9884 tid_no = ASC_TIX_TO_TID(target_ix);
9885 if ((asc_dvc->unit_not_ready & target_id) ||
9886 (asc_dvc->queue_full_or_busy & target_id)) {
9887 return (0);
9888 }
9889 if (n_qs == 1) {
9890 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9891 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9892 } else {
9893 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9894 (uint) ASC_MIN_FREE_Q;
9895 }
9896 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9897 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9898 if (asc_dvc->cur_dvc_qng[tid_no] >=
9899 asc_dvc->max_dvc_qng[tid_no]) {
9900 return (0);
9901 }
9902 return (cur_free_qs);
9903 }
9904 if (n_qs > 1) {
9905 if ((n_qs > asc_dvc->last_q_shortage)
9906 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9907 asc_dvc->last_q_shortage = n_qs;
9908 }
9909 }
9910 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009911}
9912
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009913static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009914{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009915 ushort q_addr;
9916 uchar tid_no;
9917 uchar sdtr_data;
9918 uchar syn_period_ix;
9919 uchar syn_offset;
9920 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009921
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009922 iop_base = asc_dvc->iop_base;
9923 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9924 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9925 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9926 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9927 syn_period_ix =
9928 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9929 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9930 AscMsgOutSDTR(asc_dvc,
9931 asc_dvc->sdtr_period_tbl[syn_period_ix],
9932 syn_offset);
9933 scsiq->q1.cntl |= QC_MSG_OUT;
9934 }
9935 q_addr = ASC_QNO_TO_QADDR(q_no);
9936 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9937 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9938 }
9939 scsiq->q1.status = QS_FREE;
9940 AscMemWordCopyPtrToLram(iop_base,
9941 q_addr + ASC_SCSIQ_CDB_BEG,
9942 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009944 DvcPutScsiQ(iop_base,
9945 q_addr + ASC_SCSIQ_CPY_BEG,
9946 (uchar *)&scsiq->q1.cntl,
9947 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9948 AscWriteLramWord(iop_base,
9949 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9950 (ushort)(((ushort)scsiq->q1.
9951 q_no << 8) | (ushort)QS_READY));
9952 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009953}
9954
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009955static int
9956AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009957{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009958 int sta;
9959 int i;
9960 ASC_SG_HEAD *sg_head;
9961 ASC_SG_LIST_Q scsi_sg_q;
9962 ASC_DCNT saved_data_addr;
9963 ASC_DCNT saved_data_cnt;
9964 PortAddr iop_base;
9965 ushort sg_list_dwords;
9966 ushort sg_index;
9967 ushort sg_entry_cnt;
9968 ushort q_addr;
9969 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009970
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009971 iop_base = asc_dvc->iop_base;
9972 sg_head = scsiq->sg_head;
9973 saved_data_addr = scsiq->q1.data_addr;
9974 saved_data_cnt = scsiq->q1.data_cnt;
9975 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9976 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009977#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009978 /*
9979 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9980 * then not all SG elements will fit in the allocated queues.
9981 * The rest of the SG elements will be copied when the RISC
9982 * completes the SG elements that fit and halts.
9983 */
9984 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9985 /*
9986 * Set sg_entry_cnt to be the number of SG elements that
9987 * will fit in the allocated SG queues. It is minus 1, because
9988 * the first SG element is handled above. ASC_MAX_SG_LIST is
9989 * already inflated by 1 to account for this. For example it
9990 * may be 50 which is 1 + 7 queues * 7 SG elements.
9991 */
9992 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009993
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009994 /*
9995 * Keep track of remaining number of SG elements that will
9996 * need to be handled from a_isr.c.
9997 */
9998 scsiq->remain_sg_entry_cnt =
9999 sg_head->entry_cnt - ASC_MAX_SG_LIST;
10000 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010001#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010002 /*
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.
10006 */
10007 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010008#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010010#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010011 if (sg_entry_cnt != 0) {
10012 scsiq->q1.cntl |= QC_SG_HEAD;
10013 q_addr = ASC_QNO_TO_QADDR(q_no);
10014 sg_index = 1;
10015 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
10016 scsi_sg_q.sg_head_qp = q_no;
10017 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
10018 for (i = 0; i < sg_head->queue_cnt; i++) {
10019 scsi_sg_q.seq_no = i + 1;
10020 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
10021 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
10022 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
10023 if (i == 0) {
10024 scsi_sg_q.sg_list_cnt =
10025 ASC_SG_LIST_PER_Q;
10026 scsi_sg_q.sg_cur_list_cnt =
10027 ASC_SG_LIST_PER_Q;
10028 } else {
10029 scsi_sg_q.sg_list_cnt =
10030 ASC_SG_LIST_PER_Q - 1;
10031 scsi_sg_q.sg_cur_list_cnt =
10032 ASC_SG_LIST_PER_Q - 1;
10033 }
10034 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010035#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010036 /*
10037 * This is the last SG queue in the list of
10038 * allocated SG queues. If there are more
10039 * SG elements than will fit in the allocated
10040 * queues, then set the QCSG_SG_XFER_MORE flag.
10041 */
10042 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
10043 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
10044 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010045#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010046 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010047#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010049#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010050 sg_list_dwords = sg_entry_cnt << 1;
10051 if (i == 0) {
10052 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
10053 scsi_sg_q.sg_cur_list_cnt =
10054 sg_entry_cnt;
10055 } else {
10056 scsi_sg_q.sg_list_cnt =
10057 sg_entry_cnt - 1;
10058 scsi_sg_q.sg_cur_list_cnt =
10059 sg_entry_cnt - 1;
10060 }
10061 sg_entry_cnt = 0;
10062 }
10063 next_qp = AscReadLramByte(iop_base,
10064 (ushort)(q_addr +
10065 ASC_SCSIQ_B_FWD));
10066 scsi_sg_q.q_no = next_qp;
10067 q_addr = ASC_QNO_TO_QADDR(next_qp);
10068 AscMemWordCopyPtrToLram(iop_base,
10069 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
10070 (uchar *)&scsi_sg_q,
10071 sizeof(ASC_SG_LIST_Q) >> 1);
10072 AscMemDWordCopyPtrToLram(iop_base,
10073 q_addr + ASC_SGQ_LIST_BEG,
10074 (uchar *)&sg_head->
10075 sg_list[sg_index],
10076 sg_list_dwords);
10077 sg_index += ASC_SG_LIST_PER_Q;
10078 scsiq->next_sg_index = sg_index;
10079 }
10080 } else {
10081 scsiq->q1.cntl &= ~QC_SG_HEAD;
10082 }
10083 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
10084 scsiq->q1.data_addr = saved_data_addr;
10085 scsiq->q1.data_cnt = saved_data_cnt;
10086 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010087}
10088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010089static int
10090AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010091{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010092 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010094 if (AscHostReqRiscHalt(iop_base)) {
10095 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
10096 AscStartChip(iop_base);
10097 return (sta);
10098 }
10099 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010100}
10101
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010102static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010103{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010104 ASC_SCSI_BIT_ID_TYPE org_id;
10105 int i;
10106 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010107
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010108 AscSetBank(iop_base, 1);
10109 org_id = AscReadChipDvcID(iop_base);
10110 for (i = 0; i <= ASC_MAX_TID; i++) {
10111 if (org_id == (0x01 << i))
10112 break;
10113 }
10114 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
10115 AscWriteChipDvcID(iop_base, id);
10116 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
10117 AscSetBank(iop_base, 0);
10118 AscSetChipSyn(iop_base, sdtr_data);
10119 if (AscGetChipSyn(iop_base) != sdtr_data) {
10120 sta = FALSE;
10121 }
10122 } else {
10123 sta = FALSE;
10124 }
10125 AscSetBank(iop_base, 1);
10126 AscWriteChipDvcID(iop_base, org_id);
10127 AscSetBank(iop_base, 0);
10128 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010129}
10130
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010131static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010132{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010133 uchar i;
10134 ushort s_addr;
10135 PortAddr iop_base;
10136 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010137
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010138 iop_base = asc_dvc->iop_base;
10139 warn_code = 0;
10140 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
10141 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
10142 64) >> 1)
10143 );
10144 i = ASC_MIN_ACTIVE_QNO;
10145 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
10146 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10147 (uchar)(i + 1));
10148 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10149 (uchar)(asc_dvc->max_total_qng));
10150 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10151 (uchar)i);
10152 i++;
10153 s_addr += ASC_QBLK_SIZE;
10154 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
10155 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10156 (uchar)(i + 1));
10157 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10158 (uchar)(i - 1));
10159 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10160 (uchar)i);
10161 }
10162 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10163 (uchar)ASC_QLINK_END);
10164 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10165 (uchar)(asc_dvc->max_total_qng - 1));
10166 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10167 (uchar)asc_dvc->max_total_qng);
10168 i++;
10169 s_addr += ASC_QBLK_SIZE;
10170 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
10171 i++, s_addr += ASC_QBLK_SIZE) {
10172 AscWriteLramByte(iop_base,
10173 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
10174 AscWriteLramByte(iop_base,
10175 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
10176 AscWriteLramByte(iop_base,
10177 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
10178 }
10179 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010180}
10181
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010182static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010183{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010184 PortAddr iop_base;
10185 int i;
10186 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010187
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010188 iop_base = asc_dvc->iop_base;
10189 AscPutRiscVarFreeQHead(iop_base, 1);
10190 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
10191 AscPutVarFreeQHead(iop_base, 1);
10192 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
10193 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
10194 (uchar)((int)asc_dvc->max_total_qng + 1));
10195 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
10196 (uchar)((int)asc_dvc->max_total_qng + 2));
10197 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
10198 asc_dvc->max_total_qng);
10199 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
10200 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
10201 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
10202 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
10203 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
10204 AscPutQDoneInProgress(iop_base, 0);
10205 lram_addr = ASC_QADR_BEG;
10206 for (i = 0; i < 32; i++, lram_addr += 2) {
10207 AscWriteLramWord(iop_base, lram_addr, 0);
10208 }
10209 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010210}
10211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010212static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010213{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010214 if (asc_dvc->err_code == 0) {
10215 asc_dvc->err_code = err_code;
10216 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
10217 err_code);
10218 }
10219 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010220}
10221
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010222static uchar
10223AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010224{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010225 EXT_MSG sdtr_buf;
10226 uchar sdtr_period_index;
10227 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010228
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010229 iop_base = asc_dvc->iop_base;
10230 sdtr_buf.msg_type = MS_EXTEND;
10231 sdtr_buf.msg_len = MS_SDTR_LEN;
10232 sdtr_buf.msg_req = MS_SDTR_CODE;
10233 sdtr_buf.xfer_period = sdtr_period;
10234 sdtr_offset &= ASC_SYN_MAX_OFFSET;
10235 sdtr_buf.req_ack_offset = sdtr_offset;
10236 if ((sdtr_period_index =
10237 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
10238 asc_dvc->max_sdtr_index) {
10239 AscMemWordCopyPtrToLram(iop_base,
10240 ASCV_MSGOUT_BEG,
10241 (uchar *)&sdtr_buf,
10242 sizeof(EXT_MSG) >> 1);
10243 return ((sdtr_period_index << 4) | sdtr_offset);
10244 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010245
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010246 sdtr_buf.req_ack_offset = 0;
10247 AscMemWordCopyPtrToLram(iop_base,
10248 ASCV_MSGOUT_BEG,
10249 (uchar *)&sdtr_buf,
10250 sizeof(EXT_MSG) >> 1);
10251 return (0);
10252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010253}
10254
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010255static uchar
10256AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010257{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010258 uchar byte;
10259 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010260
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010261 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
10262 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
10263 ) {
10264 return (0xFF);
10265 }
10266 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
10267 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010268}
10269
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010270static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010271{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010272 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
10273 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
10274 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010275}
10276
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010277static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010278{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010279 uchar *period_table;
10280 int max_index;
10281 int min_index;
10282 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010283
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010284 period_table = asc_dvc->sdtr_period_tbl;
10285 max_index = (int)asc_dvc->max_sdtr_index;
10286 min_index = (int)asc_dvc->host_init_sdtr_index;
10287 if ((syn_time <= period_table[max_index])) {
10288 for (i = min_index; i < (max_index - 1); i++) {
10289 if (syn_time <= period_table[i]) {
10290 return ((uchar)i);
10291 }
10292 }
10293 return ((uchar)max_index);
10294 } else {
10295 return ((uchar)(max_index + 1));
10296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010297}
10298
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010299static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010300{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010301 ushort q_addr;
10302 uchar next_qp;
10303 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010304
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010305 q_addr = ASC_QNO_TO_QADDR(free_q_head);
10306 q_status = (uchar)AscReadLramByte(iop_base,
10307 (ushort)(q_addr +
10308 ASC_SCSIQ_B_STATUS));
10309 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
10310 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
10311 return (next_qp);
10312 }
10313 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010314}
10315
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010316static uchar
10317AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010318{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010319 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010320
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010321 for (i = 0; i < n_free_q; i++) {
10322 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
10323 == ASC_QLINK_END) {
10324 return (ASC_QLINK_END);
10325 }
10326 }
10327 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010328}
10329
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010330static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010331{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010332 int count = 0;
10333 int sta = 0;
10334 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010335
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010336 if (AscIsChipHalted(iop_base))
10337 return (1);
10338 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
10339 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10340 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
10341 do {
10342 if (AscIsChipHalted(iop_base)) {
10343 sta = 1;
10344 break;
10345 }
10346 DvcSleepMilliSecond(100);
10347 } while (count++ < 20);
10348 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
10349 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010350}
10351
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010352static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010353{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010354 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010355
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010356 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
10357 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10358 ASC_STOP_REQ_RISC_STOP);
10359 do {
10360 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
10361 ASC_STOP_ACK_RISC_STOP) {
10362 return (1);
10363 }
10364 DvcSleepMilliSecond(100);
10365 } while (count++ < 20);
10366 }
10367 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010368}
10369
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010370static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010371{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010372 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010373}
10374
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010375static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010376{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010377 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010378}
10379
10380#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010381static ASC_DCNT __init AscGetEisaProductID(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010382{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010383 PortAddr eisa_iop;
10384 ushort product_id_high, product_id_low;
10385 ASC_DCNT product_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010386
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010387 eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
10388 product_id_low = inpw(eisa_iop);
10389 product_id_high = inpw(eisa_iop + 2);
10390 product_id = ((ASC_DCNT) product_id_high << 16) |
10391 (ASC_DCNT) product_id_low;
10392 return (product_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010393}
10394
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010395static PortAddr __init AscSearchIOPortAddrEISA(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010396{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010397 ASC_DCNT eisa_product_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010398
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010399 if (iop_base == 0) {
10400 iop_base = ASC_EISA_MIN_IOP_ADDR;
10401 } else {
10402 if (iop_base == ASC_EISA_MAX_IOP_ADDR)
10403 return (0);
10404 if ((iop_base & 0x0050) == 0x0050) {
10405 iop_base += ASC_EISA_BIG_IOP_GAP;
10406 } else {
10407 iop_base += ASC_EISA_SMALL_IOP_GAP;
10408 }
10409 }
10410 while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
10411 eisa_product_id = AscGetEisaProductID(iop_base);
10412 if ((eisa_product_id == ASC_EISA_ID_740) ||
10413 (eisa_product_id == ASC_EISA_ID_750)) {
10414 if (AscFindSignature(iop_base)) {
10415 inpw(iop_base + 4);
10416 return (iop_base);
10417 }
10418 }
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 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010428}
10429#endif /* CONFIG_ISA */
10430
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010431static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010432{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010433 AscSetChipControl(iop_base, 0);
10434 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10435 return (0);
10436 }
10437 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010438}
10439
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010440static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010441{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010442 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010443
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010444 cc_val =
10445 AscGetChipControl(iop_base) &
10446 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
10447 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
10448 AscSetChipIH(iop_base, INS_HALT);
10449 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10450 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
10451 return (0);
10452 }
10453 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010454}
10455
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010456static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010457{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010458 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10459 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
10460 return (1);
10461 }
10462 }
10463 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010464}
10465
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010466static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010467{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010468 AscSetBank(iop_base, 1);
10469 AscWriteChipIH(iop_base, ins_code);
10470 AscSetBank(iop_base, 0);
10471 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010472}
10473
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010474static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010475{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010476 uchar host_flag;
10477 uchar risc_flag;
10478 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010479
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010480 loop = 0;
10481 do {
10482 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10483 if (loop++ > 0x7FFF) {
10484 break;
10485 }
10486 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10487 host_flag =
10488 AscReadLramByte(iop_base,
10489 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10490 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10491 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10492 AscSetChipStatus(iop_base, CIW_INT_ACK);
10493 loop = 0;
10494 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10495 AscSetChipStatus(iop_base, CIW_INT_ACK);
10496 if (loop++ > 3) {
10497 break;
10498 }
10499 }
10500 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10501 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010502}
10503
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010504static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010505{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010506 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010507
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010508 cfg = AscGetChipCfgLsw(iop_base);
10509 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10510 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010511}
10512
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010513static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010514{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010515 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010516
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010517 cfg = AscGetChipCfgLsw(iop_base);
10518 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10519 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010520}
10521
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010522static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010523{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010524 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010525
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010526 val = AscGetChipControl(iop_base) &
10527 (~
10528 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10529 CC_CHIP_RESET));
10530 if (bank == 1) {
10531 val |= CC_BANK_ONE;
10532 } else if (bank == 2) {
10533 val |= CC_DIAG | CC_BANK_ONE;
10534 } else {
10535 val &= ~CC_BANK_ONE;
10536 }
10537 AscSetChipControl(iop_base, val);
10538 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010539}
10540
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010541static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010542{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010543 PortAddr iop_base;
10544 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010545
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010546 iop_base = asc_dvc->iop_base;
10547 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10548 && (i-- > 0)) {
10549 DvcSleepMilliSecond(100);
10550 }
10551 AscStopChip(iop_base);
10552 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10553 DvcDelayNanoSecond(asc_dvc, 60000);
10554 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10555 AscSetChipIH(iop_base, INS_HALT);
10556 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10557 AscSetChipControl(iop_base, CC_HALT);
10558 DvcSleepMilliSecond(200);
10559 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10560 AscSetChipStatus(iop_base, 0);
10561 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010562}
10563
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010564static ASC_DCNT __init AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010565{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010566 if (bus_type & ASC_IS_ISA)
10567 return (ASC_MAX_ISA_DMA_COUNT);
10568 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10569 return (ASC_MAX_VL_DMA_COUNT);
10570 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010571}
10572
10573#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010574static ushort __init AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010575{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010576 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010577
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010578 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10579 if (channel == 0x03)
10580 return (0);
10581 else if (channel == 0x00)
10582 return (7);
10583 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010584}
10585
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010586static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010587{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010588 ushort cfg_lsw;
10589 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010590
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010591 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10592 if (dma_channel == 7)
10593 value = 0x00;
10594 else
10595 value = dma_channel - 4;
10596 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10597 cfg_lsw |= value;
10598 AscSetChipCfgLsw(iop_base, cfg_lsw);
10599 return (AscGetIsaDmaChannel(iop_base));
10600 }
10601 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010602}
10603
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010604static uchar __init AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010605{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010606 speed_value &= 0x07;
10607 AscSetBank(iop_base, 1);
10608 AscWriteChipDmaSpeed(iop_base, speed_value);
10609 AscSetBank(iop_base, 0);
10610 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010611}
10612
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010613static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010614{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010615 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010616
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010617 AscSetBank(iop_base, 1);
10618 speed_value = AscReadChipDmaSpeed(iop_base);
10619 speed_value &= 0x07;
10620 AscSetBank(iop_base, 0);
10621 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010622}
10623#endif /* CONFIG_ISA */
10624
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010625static ushort __init
10626AscReadPCIConfigWord(ASC_DVC_VAR *asc_dvc, ushort pci_config_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010627{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010628 uchar lsb, msb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010630 lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
10631 msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
10632 return ((ushort)((msb << 8) | lsb));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010633}
10634
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010635static ushort __init AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010636{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010637 ushort warn_code;
10638 PortAddr iop_base;
10639 ushort PCIDeviceID;
10640 ushort PCIVendorID;
10641 uchar PCIRevisionID;
10642 uchar prevCmdRegBits;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010643
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010644 warn_code = 0;
10645 iop_base = asc_dvc->iop_base;
10646 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
10647 if (asc_dvc->err_code != 0) {
10648 return (UW_ERR);
10649 }
10650 if (asc_dvc->bus_type == ASC_IS_PCI) {
10651 PCIVendorID = AscReadPCIConfigWord(asc_dvc,
10652 AscPCIConfigVendorIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010653
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010654 PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
10655 AscPCIConfigDeviceIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010657 PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
10658 AscPCIConfigRevisionIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010659
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010660 if (PCIVendorID != PCI_VENDOR_ID_ASP) {
10661 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10662 }
10663 prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
10664 AscPCIConfigCommandRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010665
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010666 if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
10667 AscPCICmdRegBits_IOMemBusMaster) {
10668 DvcWritePCIConfigByte(asc_dvc,
10669 AscPCIConfigCommandRegister,
10670 (prevCmdRegBits |
10671 AscPCICmdRegBits_IOMemBusMaster));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010672
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010673 if ((DvcReadPCIConfigByte(asc_dvc,
10674 AscPCIConfigCommandRegister)
10675 & AscPCICmdRegBits_IOMemBusMaster)
10676 != AscPCICmdRegBits_IOMemBusMaster) {
10677 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10678 }
10679 }
10680 if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
10681 (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
10682 DvcWritePCIConfigByte(asc_dvc,
10683 AscPCIConfigLatencyTimer, 0x00);
10684 if (DvcReadPCIConfigByte
10685 (asc_dvc, AscPCIConfigLatencyTimer)
10686 != 0x00) {
10687 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10688 }
10689 } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
10690 if (DvcReadPCIConfigByte(asc_dvc,
10691 AscPCIConfigLatencyTimer) <
10692 0x20) {
10693 DvcWritePCIConfigByte(asc_dvc,
10694 AscPCIConfigLatencyTimer,
10695 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010696
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010697 if (DvcReadPCIConfigByte(asc_dvc,
10698 AscPCIConfigLatencyTimer)
10699 < 0x20) {
10700 warn_code |=
10701 ASC_WARN_SET_PCI_CONFIG_SPACE;
10702 }
10703 }
10704 }
10705 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010706
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010707 if (AscFindSignature(iop_base)) {
10708 warn_code |= AscInitAscDvcVar(asc_dvc);
10709 warn_code |= AscInitFromEEP(asc_dvc);
10710 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
10711 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
10712 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
10713 }
10714 } else {
10715 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10716 }
10717 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010718}
10719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010720static ushort __init AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010721{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010722 ushort warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010723
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010724 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10725 if (asc_dvc->err_code != 0)
10726 return (UW_ERR);
10727 if (AscFindSignature(asc_dvc->iop_base)) {
10728 warn_code |= AscInitFromAscDvcVar(asc_dvc);
10729 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10730 } else {
10731 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10732 }
10733 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010734}
10735
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010736static ushort __init AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010737{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010738 PortAddr iop_base;
10739 ushort cfg_msw;
10740 ushort warn_code;
10741 ushort pci_device_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010742
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010743 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010744#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010745 if (asc_dvc->cfg->dev)
10746 pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010747#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010748 warn_code = 0;
10749 cfg_msw = AscGetChipCfgMsw(iop_base);
10750 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10751 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10752 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10753 AscSetChipCfgMsw(iop_base, cfg_msw);
10754 }
10755 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10756 asc_dvc->cfg->cmd_qng_enabled) {
10757 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10758 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10759 }
10760 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10761 warn_code |= ASC_WARN_AUTO_CONFIG;
10762 }
10763 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10764 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10765 != asc_dvc->irq_no) {
10766 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10767 }
10768 }
10769 if (asc_dvc->bus_type & ASC_IS_PCI) {
10770 cfg_msw &= 0xFFC0;
10771 AscSetChipCfgMsw(iop_base, cfg_msw);
10772 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10773 } else {
10774 if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
10775 (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
10776 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10777 asc_dvc->bug_fix_cntl |=
10778 ASC_BUG_FIX_ASYN_USE_SYN;
10779 }
10780 }
10781 } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
10782 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10783 == ASC_CHIP_VER_ASYN_BUG) {
10784 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10785 }
10786 }
10787 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10788 asc_dvc->cfg->chip_scsi_id) {
10789 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010791#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010792 if (asc_dvc->bus_type & ASC_IS_ISA) {
10793 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10794 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010796#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010797 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010798}
10799
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010800static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010801{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010802 ushort warn_code;
10803 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010804
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010805 iop_base = asc_dvc->iop_base;
10806 warn_code = 0;
10807 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10808 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10809 AscResetChipAndScsiBus(asc_dvc);
10810 DvcSleepMilliSecond((ASC_DCNT)
10811 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10812 }
10813 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10814 if (asc_dvc->err_code != 0)
10815 return (UW_ERR);
10816 if (!AscFindSignature(asc_dvc->iop_base)) {
10817 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10818 return (warn_code);
10819 }
10820 AscDisableInterrupt(iop_base);
10821 warn_code |= AscInitLram(asc_dvc);
10822 if (asc_dvc->err_code != 0)
10823 return (UW_ERR);
10824 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10825 (ulong)_asc_mcode_chksum);
10826 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10827 _asc_mcode_size) != _asc_mcode_chksum) {
10828 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10829 return (warn_code);
10830 }
10831 warn_code |= AscInitMicroCodeVar(asc_dvc);
10832 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10833 AscEnableInterrupt(iop_base);
10834 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010835}
10836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010837static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010838{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010839 int i;
10840 PortAddr iop_base;
10841 ushort warn_code;
10842 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010843
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010844 iop_base = asc_dvc->iop_base;
10845 warn_code = 0;
10846 asc_dvc->err_code = 0;
10847 if ((asc_dvc->bus_type &
10848 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10849 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10850 }
10851 AscSetChipControl(iop_base, CC_HALT);
10852 AscSetChipStatus(iop_base, 0);
10853 asc_dvc->bug_fix_cntl = 0;
10854 asc_dvc->pci_fix_asyn_xfer = 0;
10855 asc_dvc->pci_fix_asyn_xfer_always = 0;
10856 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10857 asc_dvc->sdtr_done = 0;
10858 asc_dvc->cur_total_qng = 0;
10859 asc_dvc->is_in_int = 0;
10860 asc_dvc->in_critical_cnt = 0;
10861 asc_dvc->last_q_shortage = 0;
10862 asc_dvc->use_tagged_qng = 0;
10863 asc_dvc->no_scam = 0;
10864 asc_dvc->unit_not_ready = 0;
10865 asc_dvc->queue_full_or_busy = 0;
10866 asc_dvc->redo_scam = 0;
10867 asc_dvc->res2 = 0;
10868 asc_dvc->host_init_sdtr_index = 0;
10869 asc_dvc->cfg->can_tagged_qng = 0;
10870 asc_dvc->cfg->cmd_qng_enabled = 0;
10871 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10872 asc_dvc->init_sdtr = 0;
10873 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10874 asc_dvc->scsi_reset_wait = 3;
10875 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10876 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10877 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10878 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10879 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10880 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10881 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10882 ASC_LIB_VERSION_MINOR;
10883 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10884 asc_dvc->cfg->chip_version = chip_version;
10885 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10886 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10887 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10888 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10889 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10890 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10891 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10892 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10893 asc_dvc->max_sdtr_index = 7;
10894 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10895 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10896 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10897 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10898 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10899 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10900 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10901 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10902 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10903 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10904 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10905 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10906 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10907 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10908 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10909 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10910 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10911 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10912 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10913 asc_dvc->max_sdtr_index = 15;
10914 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10915 AscSetExtraControl(iop_base,
10916 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10917 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10918 AscSetExtraControl(iop_base,
10919 (SEC_ACTIVE_NEGATE |
10920 SEC_ENABLE_FILTER));
10921 }
10922 }
10923 if (asc_dvc->bus_type == ASC_IS_PCI) {
10924 AscSetExtraControl(iop_base,
10925 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010927
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010928 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
10929 if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
10930 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10931 asc_dvc->bus_type = ASC_IS_ISAPNP;
10932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010933#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010934 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
10935 asc_dvc->cfg->isa_dma_channel =
10936 (uchar)AscGetIsaDmaChannel(iop_base);
10937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010938#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010939 for (i = 0; i <= ASC_MAX_TID; i++) {
10940 asc_dvc->cur_dvc_qng[i] = 0;
10941 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10942 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10943 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10944 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10945 }
10946 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010947}
10948
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010949static ushort __init AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010950{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010951 ASCEEP_CONFIG eep_config_buf;
10952 ASCEEP_CONFIG *eep_config;
10953 PortAddr iop_base;
10954 ushort chksum;
10955 ushort warn_code;
10956 ushort cfg_msw, cfg_lsw;
10957 int i;
10958 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010959
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010960 iop_base = asc_dvc->iop_base;
10961 warn_code = 0;
10962 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10963 AscStopQueueExe(iop_base);
10964 if ((AscStopChip(iop_base) == FALSE) ||
10965 (AscGetChipScsiCtrl(iop_base) != 0)) {
10966 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10967 AscResetChipAndScsiBus(asc_dvc);
10968 DvcSleepMilliSecond((ASC_DCNT)
10969 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10970 }
10971 if (AscIsChipHalted(iop_base) == FALSE) {
10972 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10973 return (warn_code);
10974 }
10975 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10976 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10977 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10978 return (warn_code);
10979 }
10980 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10981 cfg_msw = AscGetChipCfgMsw(iop_base);
10982 cfg_lsw = AscGetChipCfgLsw(iop_base);
10983 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10984 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10985 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10986 AscSetChipCfgMsw(iop_base, cfg_msw);
10987 }
10988 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
10989 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
10990 if (chksum == 0) {
10991 chksum = 0xaa55;
10992 }
10993 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10994 warn_code |= ASC_WARN_AUTO_CONFIG;
10995 if (asc_dvc->cfg->chip_version == 3) {
10996 if (eep_config->cfg_lsw != cfg_lsw) {
10997 warn_code |= ASC_WARN_EEPROM_RECOVER;
10998 eep_config->cfg_lsw =
10999 AscGetChipCfgLsw(iop_base);
11000 }
11001 if (eep_config->cfg_msw != cfg_msw) {
11002 warn_code |= ASC_WARN_EEPROM_RECOVER;
11003 eep_config->cfg_msw =
11004 AscGetChipCfgMsw(iop_base);
11005 }
11006 }
11007 }
11008 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
11009 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
11010 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
11011 eep_config->chksum);
11012 if (chksum != eep_config->chksum) {
11013 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
11014 ASC_CHIP_VER_PCI_ULTRA_3050) {
11015 ASC_DBG(1,
11016 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
11017 eep_config->init_sdtr = 0xFF;
11018 eep_config->disc_enable = 0xFF;
11019 eep_config->start_motor = 0xFF;
11020 eep_config->use_cmd_qng = 0;
11021 eep_config->max_total_qng = 0xF0;
11022 eep_config->max_tag_qng = 0x20;
11023 eep_config->cntl = 0xBFFF;
11024 ASC_EEP_SET_CHIP_ID(eep_config, 7);
11025 eep_config->no_scam = 0;
11026 eep_config->adapter_info[0] = 0;
11027 eep_config->adapter_info[1] = 0;
11028 eep_config->adapter_info[2] = 0;
11029 eep_config->adapter_info[3] = 0;
11030 eep_config->adapter_info[4] = 0;
11031 /* Indicate EEPROM-less board. */
11032 eep_config->adapter_info[5] = 0xBB;
11033 } else {
11034 ASC_PRINT
11035 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
11036 write_eep = 1;
11037 warn_code |= ASC_WARN_EEPROM_CHKSUM;
11038 }
11039 }
11040 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
11041 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
11042 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
11043 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
11044 asc_dvc->start_motor = eep_config->start_motor;
11045 asc_dvc->dvc_cntl = eep_config->cntl;
11046 asc_dvc->no_scam = eep_config->no_scam;
11047 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
11048 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
11049 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
11050 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
11051 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
11052 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
11053 if (!AscTestExternalLram(asc_dvc)) {
11054 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
11055 ASC_IS_PCI_ULTRA)) {
11056 eep_config->max_total_qng =
11057 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
11058 eep_config->max_tag_qng =
11059 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
11060 } else {
11061 eep_config->cfg_msw |= 0x0800;
11062 cfg_msw |= 0x0800;
11063 AscSetChipCfgMsw(iop_base, cfg_msw);
11064 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
11065 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
11066 }
11067 } else {
11068 }
11069 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
11070 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
11071 }
11072 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
11073 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
11074 }
11075 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
11076 eep_config->max_tag_qng = eep_config->max_total_qng;
11077 }
11078 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
11079 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
11080 }
11081 asc_dvc->max_total_qng = eep_config->max_total_qng;
11082 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
11083 eep_config->use_cmd_qng) {
11084 eep_config->disc_enable = eep_config->use_cmd_qng;
11085 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
11086 }
11087 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
11088 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
11089 }
11090 ASC_EEP_SET_CHIP_ID(eep_config,
11091 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
11092 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
11093 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
11094 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
11095 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
11096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011097
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011098 for (i = 0; i <= ASC_MAX_TID; i++) {
11099 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
11100 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
11101 asc_dvc->cfg->sdtr_period_offset[i] =
11102 (uchar)(ASC_DEF_SDTR_OFFSET |
11103 (asc_dvc->host_init_sdtr_index << 4));
11104 }
11105 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
11106 if (write_eep) {
11107 if ((i =
11108 AscSetEEPConfig(iop_base, eep_config,
11109 asc_dvc->bus_type)) != 0) {
11110 ASC_PRINT1
11111 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
11112 i);
11113 } else {
11114 ASC_PRINT
11115 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
11116 }
11117 }
11118 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011119}
11120
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011121static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011122{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011123 int i;
11124 ushort warn_code;
11125 PortAddr iop_base;
11126 ASC_PADDR phy_addr;
11127 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011128
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011129 iop_base = asc_dvc->iop_base;
11130 warn_code = 0;
11131 for (i = 0; i <= ASC_MAX_TID; i++) {
11132 AscPutMCodeInitSDTRAtID(iop_base, i,
11133 asc_dvc->cfg->sdtr_period_offset[i]
11134 );
11135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011136
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011137 AscInitQLinkVar(asc_dvc);
11138 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
11139 asc_dvc->cfg->disc_enable);
11140 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
11141 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011142
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011143 /* Align overrun buffer on an 8 byte boundary. */
11144 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
11145 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
11146 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
11147 (uchar *)&phy_addr, 1);
11148 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
11149 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
11150 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011151
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011152 asc_dvc->cfg->mcode_date =
11153 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
11154 asc_dvc->cfg->mcode_version =
11155 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011156
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011157 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
11158 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
11159 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
11160 return (warn_code);
11161 }
11162 if (AscStartChip(iop_base) != 1) {
11163 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
11164 return (warn_code);
11165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011166
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011167 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011168}
11169
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011170static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011171{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011172 PortAddr iop_base;
11173 ushort q_addr;
11174 ushort saved_word;
11175 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011176
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011177 iop_base = asc_dvc->iop_base;
11178 sta = 0;
11179 q_addr = ASC_QNO_TO_QADDR(241);
11180 saved_word = AscReadLramWord(iop_base, q_addr);
11181 AscSetChipLramAddr(iop_base, q_addr);
11182 AscSetChipLramData(iop_base, 0x55AA);
11183 DvcSleepMilliSecond(10);
11184 AscSetChipLramAddr(iop_base, q_addr);
11185 if (AscGetChipLramData(iop_base) == 0x55AA) {
11186 sta = 1;
11187 AscWriteLramWord(iop_base, q_addr, saved_word);
11188 }
11189 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011190}
11191
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011192static int __init AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011193{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011194 uchar read_back;
11195 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011196
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011197 retry = 0;
11198 while (TRUE) {
11199 AscSetChipEEPCmd(iop_base, cmd_reg);
11200 DvcSleepMilliSecond(1);
11201 read_back = AscGetChipEEPCmd(iop_base);
11202 if (read_back == cmd_reg) {
11203 return (1);
11204 }
11205 if (retry++ > ASC_EEP_MAX_RETRY) {
11206 return (0);
11207 }
11208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011209}
11210
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011211static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011212{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011213 ushort read_back;
11214 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011215
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011216 retry = 0;
11217 while (TRUE) {
11218 AscSetChipEEPData(iop_base, data_reg);
11219 DvcSleepMilliSecond(1);
11220 read_back = AscGetChipEEPData(iop_base);
11221 if (read_back == data_reg) {
11222 return (1);
11223 }
11224 if (retry++ > ASC_EEP_MAX_RETRY) {
11225 return (0);
11226 }
11227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011228}
11229
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011230static void __init AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011231{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011232 DvcSleepMilliSecond(1);
11233 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011234}
11235
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011236static void __init AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011237{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011238 DvcSleepMilliSecond(20);
11239 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011240}
11241
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011242static ushort __init AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011243{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011244 ushort read_wval;
11245 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011246
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011247 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
11248 AscWaitEEPRead();
11249 cmd_reg = addr | ASC_EEP_CMD_READ;
11250 AscWriteEEPCmdReg(iop_base, cmd_reg);
11251 AscWaitEEPRead();
11252 read_wval = AscGetChipEEPData(iop_base);
11253 AscWaitEEPRead();
11254 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011255}
11256
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011257static ushort __init
11258AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011259{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011260 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011261
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011262 read_wval = AscReadEEPWord(iop_base, addr);
11263 if (read_wval != word_val) {
11264 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
11265 AscWaitEEPRead();
11266 AscWriteEEPDataReg(iop_base, word_val);
11267 AscWaitEEPRead();
11268 AscWriteEEPCmdReg(iop_base,
11269 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
11270 AscWaitEEPWrite();
11271 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
11272 AscWaitEEPRead();
11273 return (AscReadEEPWord(iop_base, addr));
11274 }
11275 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011276}
11277
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011278static ushort __init
11279AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011280{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011281 ushort wval;
11282 ushort sum;
11283 ushort *wbuf;
11284 int cfg_beg;
11285 int cfg_end;
11286 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
11287 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011288
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011289 wbuf = (ushort *)cfg_buf;
11290 sum = 0;
11291 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
11292 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11293 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
11294 sum += *wbuf;
11295 }
11296 if (bus_type & ASC_IS_VL) {
11297 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11298 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11299 } else {
11300 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11301 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11302 }
11303 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11304 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
11305 if (s_addr <= uchar_end_in_config) {
11306 /*
11307 * Swap all char fields - must unswap bytes already swapped
11308 * by AscReadEEPWord().
11309 */
11310 *wbuf = le16_to_cpu(wval);
11311 } else {
11312 /* Don't swap word field at the end - cntl field. */
11313 *wbuf = wval;
11314 }
11315 sum += wval; /* Checksum treats all EEPROM data as words. */
11316 }
11317 /*
11318 * Read the checksum word which will be compared against 'sum'
11319 * by the caller. Word field already swapped.
11320 */
11321 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
11322 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011323}
11324
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011325static int __init
11326AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011327{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011328 int n_error;
11329 ushort *wbuf;
11330 ushort word;
11331 ushort sum;
11332 int s_addr;
11333 int cfg_beg;
11334 int cfg_end;
11335 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011336
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011337 wbuf = (ushort *)cfg_buf;
11338 n_error = 0;
11339 sum = 0;
11340 /* Write two config words; AscWriteEEPWord() will swap bytes. */
11341 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11342 sum += *wbuf;
11343 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
11344 n_error++;
11345 }
11346 }
11347 if (bus_type & ASC_IS_VL) {
11348 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11349 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11350 } else {
11351 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11352 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11353 }
11354 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11355 if (s_addr <= uchar_end_in_config) {
11356 /*
11357 * This is a char field. Swap char fields before they are
11358 * swapped again by AscWriteEEPWord().
11359 */
11360 word = cpu_to_le16(*wbuf);
11361 if (word !=
11362 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
11363 n_error++;
11364 }
11365 } else {
11366 /* Don't swap word field at the end - cntl field. */
11367 if (*wbuf !=
11368 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
11369 n_error++;
11370 }
11371 }
11372 sum += *wbuf; /* Checksum calculated from word values. */
11373 }
11374 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
11375 *wbuf = sum;
11376 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
11377 n_error++;
11378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011379
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011380 /* Read EEPROM back again. */
11381 wbuf = (ushort *)cfg_buf;
11382 /*
11383 * Read two config words; Byte-swapping done by AscReadEEPWord().
11384 */
11385 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11386 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
11387 n_error++;
11388 }
11389 }
11390 if (bus_type & ASC_IS_VL) {
11391 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11392 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11393 } else {
11394 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11395 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11396 }
11397 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11398 if (s_addr <= uchar_end_in_config) {
11399 /*
11400 * Swap all char fields. Must unswap bytes already swapped
11401 * by AscReadEEPWord().
11402 */
11403 word =
11404 le16_to_cpu(AscReadEEPWord
11405 (iop_base, (uchar)s_addr));
11406 } else {
11407 /* Don't swap word field at the end - cntl field. */
11408 word = AscReadEEPWord(iop_base, (uchar)s_addr);
11409 }
11410 if (*wbuf != word) {
11411 n_error++;
11412 }
11413 }
11414 /* Read checksum; Byte swapping not needed. */
11415 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
11416 n_error++;
11417 }
11418 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011419}
11420
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011421static int __init
11422AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011423{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011424 int retry;
11425 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011426
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011427 retry = 0;
11428 while (TRUE) {
11429 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
11430 bus_type)) == 0) {
11431 break;
11432 }
11433 if (++retry > ASC_EEP_MAX_RETRY) {
11434 break;
11435 }
11436 }
11437 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011438}
11439
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011440static void
11441AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011442{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011443 uchar dvc_type;
11444 ASC_SCSI_BIT_ID_TYPE tid_bits;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011445
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011446 dvc_type = ASC_INQ_DVC_TYPE(inq);
11447 tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011448
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011449 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
11450 if (!(asc_dvc->init_sdtr & tid_bits)) {
11451 if ((dvc_type == TYPE_ROM) &&
11452 (AscCompareString((uchar *)inq->vendor_id,
11453 (uchar *)"HP ", 3) == 0)) {
11454 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
11455 }
11456 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
11457 if ((dvc_type == TYPE_PROCESSOR) ||
11458 (dvc_type == TYPE_SCANNER) ||
11459 (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) {
11460 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
11461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011462
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011463 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
11464 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
11465 tid_no,
11466 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
11467 }
11468 }
11469 }
11470 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011471}
11472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011473static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011474{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011475 if ((inq->add_len >= 32) &&
11476 (AscCompareString((uchar *)inq->vendor_id,
11477 (uchar *)"QUANTUM XP34301", 15) == 0) &&
11478 (AscCompareString((uchar *)inq->product_rev_level,
11479 (uchar *)"1071", 4) == 0)) {
11480 return 0;
11481 }
11482 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011483}
11484
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011485static void
11486AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011487{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011488 ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
11489 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011490
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011491 orig_init_sdtr = asc_dvc->init_sdtr;
11492 orig_use_tagged_qng = asc_dvc->use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011494 asc_dvc->init_sdtr &= ~tid_bit;
11495 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
11496 asc_dvc->use_tagged_qng &= ~tid_bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011497
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011498 if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
11499 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
11500 asc_dvc->init_sdtr |= tid_bit;
11501 }
11502 if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
11503 ASC_INQ_CMD_QUEUE(inq)) {
11504 if (AscTagQueuingSafe(inq)) {
11505 asc_dvc->use_tagged_qng |= tid_bit;
11506 asc_dvc->cfg->can_tagged_qng |= tid_bit;
11507 }
11508 }
11509 }
11510 if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
11511 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
11512 asc_dvc->cfg->disc_enable);
11513 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
11514 asc_dvc->use_tagged_qng);
11515 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
11516 asc_dvc->cfg->can_tagged_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011517
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011518 asc_dvc->max_dvc_qng[tid_no] =
11519 asc_dvc->cfg->max_tag_qng[tid_no];
11520 AscWriteLramByte(asc_dvc->iop_base,
11521 (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no),
11522 asc_dvc->max_dvc_qng[tid_no]);
11523 }
11524 if (orig_init_sdtr != asc_dvc->init_sdtr) {
11525 AscAsyncFix(asc_dvc, tid_no, inq);
11526 }
11527 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011528}
11529
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011530static int AscCompareString(uchar *str1, uchar *str2, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011531{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011532 int i;
11533 int diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011535 for (i = 0; i < len; i++) {
11536 diff = (int)(str1[i] - str2[i]);
11537 if (diff != 0)
11538 return (diff);
11539 }
11540 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011541}
11542
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011543static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011544{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011545 uchar byte_data;
11546 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011547
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011548 if (isodd_word(addr)) {
11549 AscSetChipLramAddr(iop_base, addr - 1);
11550 word_data = AscGetChipLramData(iop_base);
11551 byte_data = (uchar)((word_data >> 8) & 0xFF);
11552 } else {
11553 AscSetChipLramAddr(iop_base, addr);
11554 word_data = AscGetChipLramData(iop_base);
11555 byte_data = (uchar)(word_data & 0xFF);
11556 }
11557 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011558}
Linus Torvalds1da177e2005-04-16 15:20:36 -070011559
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011560static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
11561{
11562 ushort word_data;
11563
11564 AscSetChipLramAddr(iop_base, addr);
11565 word_data = AscGetChipLramData(iop_base);
11566 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011567}
11568
11569#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011570static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011571{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011572 ushort val_low, val_high;
11573 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011575 AscSetChipLramAddr(iop_base, addr);
11576 val_low = AscGetChipLramData(iop_base);
11577 val_high = AscGetChipLramData(iop_base);
11578 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
11579 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011580}
11581#endif /* CC_VERY_LONG_SG_LIST */
11582
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011583static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011584{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011585 AscSetChipLramAddr(iop_base, addr);
11586 AscSetChipLramData(iop_base, word_val);
11587 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011588}
11589
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011590static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011591{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011592 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011593
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011594 if (isodd_word(addr)) {
11595 addr--;
11596 word_data = AscReadLramWord(iop_base, addr);
11597 word_data &= 0x00FF;
11598 word_data |= (((ushort)byte_val << 8) & 0xFF00);
11599 } else {
11600 word_data = AscReadLramWord(iop_base, addr);
11601 word_data &= 0xFF00;
11602 word_data |= ((ushort)byte_val & 0x00FF);
11603 }
11604 AscWriteLramWord(iop_base, addr, word_data);
11605 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011606}
11607
11608/*
11609 * Copy 2 bytes to LRAM.
11610 *
11611 * The source data is assumed to be in little-endian order in memory
11612 * and is maintained in little-endian order when written to LRAM.
11613 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011614static void
11615AscMemWordCopyPtrToLram(PortAddr iop_base,
11616 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011617{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011618 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011619
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011620 AscSetChipLramAddr(iop_base, s_addr);
11621 for (i = 0; i < 2 * words; i += 2) {
11622 /*
11623 * On a little-endian system the second argument below
11624 * produces a little-endian ushort which is written to
11625 * LRAM in little-endian order. On a big-endian system
11626 * the second argument produces a big-endian ushort which
11627 * is "transparently" byte-swapped by outpw() and written
11628 * in little-endian order to LRAM.
11629 */
11630 outpw(iop_base + IOP_RAM_DATA,
11631 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
11632 }
11633 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011634}
11635
11636/*
11637 * Copy 4 bytes to LRAM.
11638 *
11639 * The source data is assumed to be in little-endian order in memory
11640 * and is maintained in little-endian order when writen to LRAM.
11641 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011642static void
11643AscMemDWordCopyPtrToLram(PortAddr iop_base,
11644 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011645{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011646 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011647
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011648 AscSetChipLramAddr(iop_base, s_addr);
11649 for (i = 0; i < 4 * dwords; i += 4) {
11650 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11651 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11652 }
11653 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011654}
11655
11656/*
11657 * Copy 2 bytes from LRAM.
11658 *
11659 * The source data is assumed to be in little-endian order in LRAM
11660 * and is maintained in little-endian order when written to memory.
11661 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011662static void
11663AscMemWordCopyPtrFromLram(PortAddr iop_base,
11664 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011665{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011666 int i;
11667 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011668
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011669 AscSetChipLramAddr(iop_base, s_addr);
11670 for (i = 0; i < 2 * words; i += 2) {
11671 word = inpw(iop_base + IOP_RAM_DATA);
11672 d_buffer[i] = word & 0xff;
11673 d_buffer[i + 1] = (word >> 8) & 0xff;
11674 }
11675 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011676}
11677
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011678static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011679{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011680 ASC_DCNT sum;
11681 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011682
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011683 sum = 0L;
11684 for (i = 0; i < words; i++, s_addr += 2) {
11685 sum += AscReadLramWord(iop_base, s_addr);
11686 }
11687 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011688}
11689
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011690static void
11691AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011692{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011693 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011694
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011695 AscSetChipLramAddr(iop_base, s_addr);
11696 for (i = 0; i < words; i++) {
11697 AscSetChipLramData(iop_base, set_wval);
11698 }
11699 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011700}
11701
Linus Torvalds1da177e2005-04-16 15:20:36 -070011702/*
11703 * --- Adv Library Functions
11704 */
11705
11706/* a_mcode.h */
11707
11708/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011709static unsigned char _adv_asc3550_buf[] = {
11710 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11711 0x01, 0x00, 0x48, 0xe4,
11712 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11713 0x28, 0x0e, 0x9e, 0xe7,
11714 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11715 0x55, 0xf0, 0x01, 0xf6,
11716 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11717 0x00, 0xec, 0x85, 0xf0,
11718 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11719 0x86, 0xf0, 0xb4, 0x00,
11720 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11721 0xaa, 0x18, 0x02, 0x80,
11722 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11723 0x00, 0x57, 0x01, 0xea,
11724 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11725 0x03, 0xe6, 0xb6, 0x00,
11726 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11727 0x02, 0x4a, 0xb9, 0x54,
11728 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11729 0x3e, 0x00, 0x80, 0x00,
11730 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11731 0x74, 0x01, 0x76, 0x01,
11732 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11733 0x4c, 0x1c, 0xbb, 0x55,
11734 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11735 0x03, 0xf7, 0x06, 0xf7,
11736 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11737 0x30, 0x13, 0x64, 0x15,
11738 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11739 0x04, 0xea, 0x5d, 0xf0,
11740 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11741 0xcc, 0x00, 0x20, 0x01,
11742 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11743 0x40, 0x13, 0x30, 0x1c,
11744 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11745 0x59, 0xf0, 0xa7, 0xf0,
11746 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11747 0xa4, 0x00, 0xb5, 0x00,
11748 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11749 0x14, 0x0e, 0x02, 0x10,
11750 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11751 0x10, 0x15, 0x14, 0x15,
11752 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11753 0x91, 0x44, 0x0a, 0x45,
11754 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11755 0x83, 0x59, 0x05, 0xe6,
11756 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11757 0x02, 0xfa, 0x03, 0xfa,
11758 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11759 0x9e, 0x00, 0xa8, 0x00,
11760 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11761 0x7a, 0x01, 0xc0, 0x01,
11762 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11763 0x69, 0x08, 0xba, 0x08,
11764 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11765 0xf1, 0x10, 0x06, 0x12,
11766 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11767 0x8a, 0x15, 0xc6, 0x17,
11768 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11769 0x0e, 0x47, 0x48, 0x47,
11770 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11771 0x14, 0x56, 0x77, 0x57,
11772 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11773 0xf0, 0x29, 0x02, 0xfe,
11774 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11775 0xfe, 0x80, 0x01, 0xff,
11776 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11777 0x00, 0xfe, 0x57, 0x24,
11778 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11779 0x00, 0x00, 0xff, 0x08,
11780 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11781 0xff, 0xff, 0xff, 0x0f,
11782 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11783 0xfe, 0x04, 0xf7, 0xcf,
11784 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11785 0x0b, 0x3c, 0x2a, 0xfe,
11786 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11787 0xfe, 0xf0, 0x01, 0xfe,
11788 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11789 0x02, 0xfe, 0xd4, 0x0c,
11790 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11791 0x1c, 0x05, 0xfe, 0xa6,
11792 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11793 0xf0, 0xfe, 0x86, 0x02,
11794 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11795 0xfe, 0x46, 0xf0, 0xfe,
11796 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11797 0x44, 0x02, 0xfe, 0x44,
11798 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11799 0xa0, 0x17, 0x06, 0x18,
11800 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11801 0x1e, 0x1c, 0xfe, 0xe9,
11802 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11803 0x0a, 0x6b, 0x01, 0x9e,
11804 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11805 0x01, 0x82, 0xfe, 0xbd,
11806 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11807 0x58, 0x1c, 0x17, 0x06,
11808 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11809 0xfe, 0x94, 0x02, 0xfe,
11810 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11811 0x01, 0xfe, 0x54, 0x0f,
11812 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11813 0x69, 0x10, 0x17, 0x06,
11814 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11815 0xf6, 0xc7, 0x01, 0xfe,
11816 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11817 0x02, 0x29, 0x0a, 0x40,
11818 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11819 0x58, 0x0a, 0x99, 0x01,
11820 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11821 0x2a, 0x46, 0xfe, 0x02,
11822 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11823 0x01, 0xfe, 0x07, 0x4b,
11824 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11825 0xfe, 0x56, 0x03, 0xfe,
11826 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11827 0xfe, 0x9f, 0xf0, 0xfe,
11828 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11829 0x1c, 0xeb, 0x09, 0x04,
11830 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11831 0x01, 0x0e, 0xac, 0x75,
11832 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11833 0xfe, 0x82, 0xf0, 0xfe,
11834 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11835 0x32, 0x1f, 0xfe, 0xb4,
11836 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11837 0x0a, 0xf0, 0xfe, 0x7a,
11838 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11839 0x01, 0x33, 0x8f, 0xfe,
11840 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11841 0xf7, 0xfe, 0x48, 0x1c,
11842 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11843 0x0a, 0xca, 0x01, 0x0e,
11844 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11845 0x2c, 0x01, 0x33, 0x8f,
11846 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11847 0xfe, 0x3c, 0x04, 0x1f,
11848 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11849 0x12, 0x2b, 0xff, 0x02,
11850 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11851 0x22, 0x30, 0x2e, 0xd5,
11852 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11853 0xfe, 0x4c, 0x54, 0x64,
11854 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11855 0xfe, 0x2a, 0x13, 0x2f,
11856 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11857 0xd3, 0xfa, 0xef, 0x86,
11858 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11859 0x1d, 0xfe, 0x1c, 0x12,
11860 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11861 0x70, 0x0c, 0x02, 0x22,
11862 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11863 0x01, 0x33, 0x02, 0x29,
11864 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11865 0x80, 0xfe, 0x31, 0xe4,
11866 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11867 0xfe, 0x70, 0x12, 0x49,
11868 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11869 0x80, 0x05, 0xfe, 0x31,
11870 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11871 0x28, 0xfe, 0x42, 0x12,
11872 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11873 0x11, 0xfe, 0xe3, 0x00,
11874 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11875 0x64, 0x05, 0x83, 0x24,
11876 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11877 0x09, 0x48, 0x01, 0x08,
11878 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11879 0x86, 0x24, 0x06, 0x12,
11880 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11881 0x01, 0xa7, 0x14, 0x92,
11882 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11883 0x02, 0x22, 0x05, 0xfe,
11884 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11885 0x47, 0x01, 0xa7, 0x26,
11886 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11887 0x01, 0xfe, 0xaa, 0x14,
11888 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11889 0x05, 0x50, 0xb4, 0x0c,
11890 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11891 0x13, 0x01, 0xfe, 0x14,
11892 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11893 0xff, 0x02, 0x00, 0x57,
11894 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11895 0x72, 0x06, 0x49, 0x04,
11896 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11897 0x06, 0x11, 0x9a, 0x01,
11898 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11899 0x01, 0xa7, 0xec, 0x72,
11900 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11901 0xfe, 0x0a, 0xf0, 0xfe,
11902 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11903 0x8d, 0x81, 0x02, 0x22,
11904 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11905 0x01, 0x08, 0x15, 0x00,
11906 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11907 0x00, 0x02, 0xfe, 0x32,
11908 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11909 0xfe, 0x1b, 0x00, 0x01,
11910 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11911 0x08, 0x15, 0x06, 0x01,
11912 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11913 0x9a, 0x81, 0x4b, 0x1d,
11914 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11915 0x45, 0xfe, 0x32, 0x12,
11916 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11917 0xfe, 0x32, 0x07, 0x8d,
11918 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11919 0x06, 0x15, 0x19, 0x02,
11920 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11921 0x90, 0x77, 0xfe, 0xca,
11922 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11923 0x10, 0xfe, 0x0e, 0x12,
11924 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11925 0x83, 0xe7, 0xc4, 0xa1,
11926 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11927 0x40, 0x12, 0x58, 0x01,
11928 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11929 0x51, 0x83, 0xfb, 0xfe,
11930 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11931 0xfe, 0x40, 0x50, 0xfe,
11932 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11933 0xfe, 0x2a, 0x12, 0xfe,
11934 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11935 0x85, 0x01, 0xa8, 0xfe,
11936 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11937 0x18, 0x57, 0xfb, 0xfe,
11938 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11939 0x0c, 0x39, 0x18, 0x3a,
11940 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11941 0x11, 0x65, 0xfe, 0x48,
11942 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11943 0xdd, 0xb8, 0xfe, 0x80,
11944 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11945 0xfe, 0x7a, 0x08, 0x8d,
11946 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11947 0x10, 0x61, 0x04, 0x06,
11948 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11949 0x12, 0xfe, 0x2e, 0x1c,
11950 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11951 0x52, 0x12, 0xfe, 0x2c,
11952 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11953 0x08, 0xfe, 0x8a, 0x10,
11954 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11955 0x24, 0x0a, 0xab, 0xfe,
11956 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11957 0x1c, 0x12, 0xb5, 0xfe,
11958 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11959 0x1c, 0x06, 0x16, 0x9d,
11960 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11961 0x14, 0x92, 0x01, 0x33,
11962 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11963 0xfe, 0x74, 0x18, 0x1c,
11964 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11965 0x01, 0xe6, 0x1e, 0x27,
11966 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11967 0x09, 0x04, 0x6a, 0xfe,
11968 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11969 0xfe, 0x83, 0x80, 0xfe,
11970 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11971 0x27, 0xfe, 0x40, 0x59,
11972 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11973 0x7c, 0xbe, 0x54, 0xbf,
11974 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11975 0x79, 0x56, 0x68, 0x57,
11976 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11977 0xa2, 0x23, 0x0c, 0x7b,
11978 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11979 0x16, 0xd7, 0x79, 0x39,
11980 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11981 0xfe, 0x10, 0x58, 0xfe,
11982 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
11983 0x19, 0x16, 0xd7, 0x09,
11984 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
11985 0xfe, 0x10, 0x90, 0xfe,
11986 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
11987 0x11, 0x9b, 0x09, 0x04,
11988 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
11989 0xfe, 0x0c, 0x58, 0xfe,
11990 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
11991 0x0b, 0xfe, 0x1a, 0x12,
11992 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
11993 0x14, 0x7a, 0x01, 0x33,
11994 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
11995 0xfe, 0xed, 0x19, 0xbf,
11996 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
11997 0x34, 0xfe, 0x74, 0x10,
11998 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
11999 0x84, 0x05, 0xcb, 0x1c,
12000 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
12001 0xf0, 0xfe, 0xc4, 0x0a,
12002 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
12003 0xce, 0xf0, 0xfe, 0xca,
12004 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
12005 0x22, 0x00, 0x02, 0x5a,
12006 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
12007 0xfe, 0xd0, 0xf0, 0xfe,
12008 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
12009 0x4c, 0xfe, 0x10, 0x10,
12010 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
12011 0x2a, 0x13, 0xfe, 0x4e,
12012 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
12013 0x16, 0x32, 0x2a, 0x73,
12014 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
12015 0x32, 0x8c, 0xfe, 0x48,
12016 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
12017 0xdb, 0x10, 0x11, 0xfe,
12018 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
12019 0x22, 0x30, 0x2e, 0xd8,
12020 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
12021 0x45, 0x0f, 0xfe, 0x42,
12022 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
12023 0x09, 0x04, 0x0b, 0xfe,
12024 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
12025 0x00, 0x21, 0xfe, 0xa6,
12026 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
12027 0xfe, 0xe2, 0x10, 0x01,
12028 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
12029 0x01, 0x6f, 0x02, 0x29,
12030 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
12031 0x01, 0x86, 0x3e, 0x0b,
12032 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
12033 0x3e, 0x0b, 0x0f, 0xfe,
12034 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
12035 0xe8, 0x59, 0x11, 0x2d,
12036 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
12037 0x04, 0x0b, 0x84, 0x3e,
12038 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
12039 0x09, 0x04, 0x1b, 0xfe,
12040 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
12041 0x1c, 0x1c, 0xfe, 0x9d,
12042 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
12043 0xfe, 0x15, 0x00, 0xfe,
12044 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
12045 0x0f, 0xfe, 0x47, 0x00,
12046 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
12047 0xab, 0x70, 0x05, 0x6b,
12048 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
12049 0x1c, 0x42, 0x59, 0x01,
12050 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
12051 0x00, 0x37, 0x97, 0x01,
12052 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
12053 0x1d, 0xfe, 0xce, 0x45,
12054 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
12055 0x57, 0x05, 0x51, 0xfe,
12056 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
12057 0x46, 0x09, 0x04, 0x1d,
12058 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
12059 0x99, 0x01, 0x0e, 0xfe,
12060 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
12061 0xfe, 0xee, 0x14, 0xee,
12062 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
12063 0x13, 0x02, 0x29, 0x1e,
12064 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
12065 0xce, 0x1e, 0x2d, 0x47,
12066 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
12067 0x12, 0x4d, 0x01, 0xfe,
12068 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
12069 0xf0, 0x0d, 0xfe, 0x02,
12070 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
12071 0xf6, 0xfe, 0x34, 0x01,
12072 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
12073 0xaf, 0xfe, 0x02, 0xea,
12074 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
12075 0x05, 0xfe, 0x38, 0x01,
12076 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
12077 0x0c, 0xfe, 0x62, 0x01,
12078 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
12079 0x03, 0x23, 0x03, 0x1e,
12080 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
12081 0x71, 0x13, 0xfe, 0x24,
12082 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
12083 0xdc, 0xfe, 0x73, 0x57,
12084 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
12085 0x80, 0x5d, 0x03, 0xfe,
12086 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
12087 0x75, 0x03, 0x09, 0x04,
12088 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
12089 0xfe, 0x1e, 0x80, 0xe1,
12090 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
12091 0x90, 0xa3, 0xfe, 0x3c,
12092 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
12093 0x16, 0x2f, 0x07, 0x2d,
12094 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
12095 0xe8, 0x11, 0xfe, 0xe9,
12096 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
12097 0x1e, 0x1c, 0xfe, 0x14,
12098 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
12099 0x09, 0x04, 0x4f, 0xfe,
12100 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
12101 0x40, 0x12, 0x20, 0x63,
12102 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
12103 0x1c, 0x05, 0xfe, 0xac,
12104 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
12105 0xfe, 0xb0, 0x00, 0xfe,
12106 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
12107 0x24, 0x69, 0x12, 0xc9,
12108 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
12109 0x90, 0x4d, 0xfe, 0x91,
12110 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
12111 0xfe, 0x90, 0x4d, 0xfe,
12112 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
12113 0x46, 0x1e, 0x20, 0xed,
12114 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
12115 0x70, 0xfe, 0x14, 0x1c,
12116 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
12117 0xfe, 0x07, 0xe6, 0x1d,
12118 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
12119 0xfa, 0xef, 0xfe, 0x42,
12120 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
12121 0xfe, 0x36, 0x12, 0xf0,
12122 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
12123 0x3d, 0x75, 0x07, 0x10,
12124 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
12125 0x10, 0x07, 0x7e, 0x45,
12126 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
12127 0xfe, 0x01, 0xec, 0x97,
12128 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
12129 0x27, 0x01, 0xda, 0xfe,
12130 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
12131 0xfe, 0x48, 0x12, 0x07,
12132 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
12133 0xfe, 0x3e, 0x11, 0x07,
12134 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
12135 0x11, 0x07, 0x19, 0xfe,
12136 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
12137 0x01, 0x08, 0x8c, 0x43,
12138 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
12139 0x7e, 0x02, 0x29, 0x2b,
12140 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
12141 0xfc, 0x10, 0x09, 0x04,
12142 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
12143 0xc6, 0x10, 0x1e, 0x58,
12144 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
12145 0x54, 0x18, 0x55, 0x23,
12146 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
12147 0xa5, 0xc0, 0x38, 0xc1,
12148 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
12149 0x05, 0xfa, 0x4e, 0xfe,
12150 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
12151 0x0c, 0x56, 0x18, 0x57,
12152 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
12153 0x00, 0x56, 0xfe, 0xa1,
12154 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
12155 0x58, 0xfe, 0x1f, 0x40,
12156 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
12157 0x31, 0x57, 0xfe, 0x44,
12158 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
12159 0x8a, 0x50, 0x05, 0x39,
12160 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
12161 0x12, 0xcd, 0x02, 0x5b,
12162 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
12163 0x2f, 0x07, 0x9b, 0x21,
12164 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
12165 0x39, 0x68, 0x3a, 0xfe,
12166 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
12167 0x51, 0xfe, 0x8e, 0x51,
12168 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
12169 0x01, 0x08, 0x25, 0x32,
12170 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
12171 0x3b, 0x02, 0x44, 0x01,
12172 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
12173 0x01, 0x08, 0x1f, 0xa2,
12174 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
12175 0x00, 0x28, 0x84, 0x49,
12176 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
12177 0x78, 0x3d, 0xfe, 0xda,
12178 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
12179 0x05, 0xc6, 0x28, 0x84,
12180 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
12181 0x14, 0xfe, 0x03, 0x17,
12182 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
12183 0xfe, 0xaa, 0x14, 0x02,
12184 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
12185 0x21, 0x44, 0x01, 0xfe,
12186 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
12187 0xfe, 0x4a, 0xf4, 0x0b,
12188 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
12189 0x85, 0x02, 0x5b, 0x05,
12190 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
12191 0xd8, 0x14, 0x02, 0x5c,
12192 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
12193 0x01, 0x08, 0x23, 0x72,
12194 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
12195 0x12, 0x5e, 0x2b, 0x01,
12196 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
12197 0x1c, 0xfe, 0xff, 0x7f,
12198 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
12199 0x57, 0x48, 0x8b, 0x1c,
12200 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
12201 0x00, 0x57, 0x48, 0x8b,
12202 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
12203 0x03, 0x0a, 0x50, 0x01,
12204 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
12205 0x54, 0xfe, 0x00, 0xf4,
12206 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
12207 0x03, 0x7c, 0x63, 0x27,
12208 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
12209 0xfe, 0x82, 0x4a, 0xfe,
12210 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
12211 0x42, 0x48, 0x5f, 0x60,
12212 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
12213 0x1f, 0xfe, 0xa2, 0x14,
12214 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
12215 0xcc, 0x12, 0x49, 0x04,
12216 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
12217 0xe8, 0x13, 0x3b, 0x13,
12218 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
12219 0xa1, 0xff, 0x02, 0x83,
12220 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
12221 0x13, 0x06, 0xfe, 0x56,
12222 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
12223 0x64, 0x00, 0x17, 0x93,
12224 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
12225 0xc8, 0x00, 0x8e, 0xe4,
12226 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
12227 0x01, 0xba, 0xfe, 0x4e,
12228 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
12229 0xfe, 0x60, 0x14, 0xfe,
12230 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
12231 0xfe, 0x22, 0x13, 0x1c,
12232 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
12233 0xfe, 0x9c, 0x14, 0xb7,
12234 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
12235 0xfe, 0x9c, 0x14, 0xb7,
12236 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
12237 0xfe, 0xb4, 0x56, 0xfe,
12238 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
12239 0xe5, 0x15, 0x0b, 0x01,
12240 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
12241 0x49, 0x01, 0x08, 0x03,
12242 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
12243 0x15, 0x06, 0x01, 0x08,
12244 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
12245 0x4a, 0x01, 0x08, 0x03,
12246 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
12247 0xfe, 0x49, 0xf4, 0x00,
12248 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
12249 0x08, 0x2f, 0x07, 0xfe,
12250 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
12251 0x01, 0x43, 0x1e, 0xcd,
12252 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
12253 0xed, 0x88, 0x07, 0x10,
12254 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
12255 0x80, 0x01, 0x0e, 0x88,
12256 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
12257 0x88, 0x03, 0x0a, 0x42,
12258 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
12259 0xfe, 0x80, 0x80, 0xf2,
12260 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
12261 0x01, 0x82, 0x03, 0x17,
12262 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
12263 0xfe, 0x24, 0x1c, 0xfe,
12264 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
12265 0x91, 0x1d, 0x66, 0xfe,
12266 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
12267 0xda, 0x10, 0x17, 0x10,
12268 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
12269 0x05, 0xfe, 0x66, 0x01,
12270 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
12271 0xfe, 0x3c, 0x50, 0x66,
12272 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
12273 0x40, 0x16, 0xfe, 0xb6,
12274 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
12275 0x10, 0x71, 0xfe, 0x83,
12276 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
12277 0xfe, 0x62, 0x16, 0xfe,
12278 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
12279 0xfe, 0x98, 0xe7, 0x00,
12280 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
12281 0xfe, 0x30, 0xbc, 0xfe,
12282 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12283 0xc5, 0x90, 0xfe, 0x9a,
12284 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
12285 0x42, 0x10, 0xfe, 0x02,
12286 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
12287 0xfe, 0x1d, 0xf7, 0x4f,
12288 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
12289 0x47, 0xfe, 0x83, 0x58,
12290 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
12291 0xfe, 0xdd, 0x00, 0x63,
12292 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
12293 0x06, 0x37, 0x95, 0xa9,
12294 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
12295 0x18, 0x1c, 0x1a, 0x5d,
12296 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
12297 0xe1, 0x10, 0x78, 0x2c,
12298 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
12299 0x13, 0x3c, 0x8a, 0x0a,
12300 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
12301 0xe3, 0xfe, 0x00, 0xcc,
12302 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
12303 0x0e, 0xf2, 0x01, 0x6f,
12304 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
12305 0xf6, 0xfe, 0xd6, 0xf0,
12306 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
12307 0x15, 0x00, 0x59, 0x76,
12308 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
12309 0x11, 0x2d, 0x01, 0x6f,
12310 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
12311 0xc8, 0xfe, 0x48, 0x55,
12312 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
12313 0x99, 0x01, 0x0e, 0xf0,
12314 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
12315 0x75, 0x03, 0x0a, 0x42,
12316 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
12317 0x0e, 0x73, 0x75, 0x03,
12318 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
12319 0xfe, 0x3a, 0x45, 0x5b,
12320 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
12321 0xfe, 0x02, 0xe6, 0x1b,
12322 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
12323 0xfe, 0x94, 0x00, 0xfe,
12324 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
12325 0xe6, 0x2c, 0xfe, 0x4e,
12326 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
12327 0x03, 0x07, 0x7a, 0xfe,
12328 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12329 0x07, 0x1b, 0xfe, 0x5a,
12330 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
12331 0x24, 0x2c, 0xdc, 0x07,
12332 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
12333 0x9f, 0xad, 0x03, 0x14,
12334 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
12335 0x03, 0x25, 0xfe, 0xca,
12336 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
12337 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012338};
12339
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012340static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
12341static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012342
12343/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012344static unsigned char _adv_asc38C0800_buf[] = {
12345 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
12346 0x01, 0x00, 0x48, 0xe4,
12347 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
12348 0x1c, 0x0f, 0x00, 0xf6,
12349 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
12350 0x09, 0xe7, 0x55, 0xf0,
12351 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
12352 0x18, 0xf4, 0x08, 0x00,
12353 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
12354 0x86, 0xf0, 0xb1, 0xf0,
12355 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
12356 0x3c, 0x00, 0xbb, 0x00,
12357 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
12358 0xba, 0x13, 0x18, 0x40,
12359 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
12360 0x6e, 0x01, 0x74, 0x01,
12361 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
12362 0xc0, 0x00, 0x01, 0x01,
12363 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
12364 0x08, 0x12, 0x02, 0x4a,
12365 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
12366 0x5d, 0xf0, 0x02, 0xfa,
12367 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
12368 0x68, 0x01, 0x6a, 0x01,
12369 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
12370 0x06, 0x13, 0x4c, 0x1c,
12371 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
12372 0x0f, 0x00, 0x47, 0x00,
12373 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
12374 0x4e, 0x1c, 0x10, 0x44,
12375 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
12376 0x05, 0x00, 0x34, 0x00,
12377 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
12378 0x42, 0x0c, 0x12, 0x0f,
12379 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
12380 0x00, 0x4e, 0x42, 0x54,
12381 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
12382 0x59, 0xf0, 0xb8, 0xf0,
12383 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
12384 0x19, 0x00, 0x33, 0x00,
12385 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
12386 0xe7, 0x00, 0xe2, 0x03,
12387 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
12388 0x12, 0x13, 0x24, 0x14,
12389 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
12390 0x36, 0x1c, 0x08, 0x44,
12391 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
12392 0x3a, 0x55, 0x83, 0x55,
12393 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
12394 0x0c, 0xf0, 0x04, 0xf8,
12395 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
12396 0xa8, 0x00, 0xaa, 0x00,
12397 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
12398 0xc4, 0x01, 0xc6, 0x01,
12399 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
12400 0x68, 0x08, 0x69, 0x08,
12401 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
12402 0xed, 0x10, 0xf1, 0x10,
12403 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
12404 0x1e, 0x13, 0x46, 0x14,
12405 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
12406 0xca, 0x18, 0xe6, 0x19,
12407 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
12408 0xf0, 0x2b, 0x02, 0xfe,
12409 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
12410 0xfe, 0x84, 0x01, 0xff,
12411 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12412 0x00, 0xfe, 0x57, 0x24,
12413 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
12414 0x00, 0x00, 0xff, 0x08,
12415 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12416 0xff, 0xff, 0xff, 0x11,
12417 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12418 0xfe, 0x04, 0xf7, 0xd6,
12419 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
12420 0x0a, 0x42, 0x2c, 0xfe,
12421 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
12422 0xfe, 0xf4, 0x01, 0xfe,
12423 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
12424 0x02, 0xfe, 0xc8, 0x0d,
12425 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
12426 0x1c, 0x03, 0xfe, 0xa6,
12427 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
12428 0xf0, 0xfe, 0x8a, 0x02,
12429 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
12430 0xfe, 0x46, 0xf0, 0xfe,
12431 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
12432 0x48, 0x02, 0xfe, 0x44,
12433 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
12434 0xaa, 0x18, 0x06, 0x14,
12435 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
12436 0x1e, 0x1c, 0xfe, 0xe9,
12437 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
12438 0x09, 0x70, 0x01, 0xa8,
12439 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
12440 0x01, 0x87, 0xfe, 0xbd,
12441 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
12442 0x58, 0x1c, 0x18, 0x06,
12443 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
12444 0xfe, 0x98, 0x02, 0xfe,
12445 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
12446 0x01, 0xfe, 0x48, 0x10,
12447 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
12448 0x69, 0x10, 0x18, 0x06,
12449 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
12450 0xf6, 0xce, 0x01, 0xfe,
12451 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
12452 0x82, 0x16, 0x02, 0x2b,
12453 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
12454 0xfe, 0x41, 0x58, 0x09,
12455 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
12456 0x82, 0x16, 0x02, 0x2b,
12457 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
12458 0xfe, 0x77, 0x57, 0xfe,
12459 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
12460 0xfe, 0x40, 0x1c, 0x1c,
12461 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
12462 0x03, 0xfe, 0x11, 0xf0,
12463 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
12464 0xfe, 0x11, 0x00, 0x02,
12465 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
12466 0x21, 0x22, 0xa3, 0xb7,
12467 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
12468 0x12, 0xd1, 0x1c, 0xd9,
12469 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
12470 0xfe, 0xe4, 0x00, 0x27,
12471 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
12472 0x06, 0xf0, 0xfe, 0xc8,
12473 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
12474 0x70, 0x28, 0x17, 0xfe,
12475 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
12476 0xf9, 0x2c, 0x99, 0x19,
12477 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
12478 0x74, 0x01, 0xaf, 0x8c,
12479 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
12480 0x8d, 0x51, 0x64, 0x79,
12481 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
12482 0xfe, 0x6a, 0x02, 0x02,
12483 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
12484 0xfe, 0x3c, 0x04, 0x3b,
12485 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
12486 0x00, 0x10, 0x01, 0x0b,
12487 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
12488 0xfe, 0x4c, 0x44, 0xfe,
12489 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
12490 0xda, 0x4f, 0x79, 0x2a,
12491 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
12492 0xfe, 0x2a, 0x13, 0x32,
12493 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
12494 0x54, 0x6b, 0xda, 0xfe,
12495 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
12496 0x08, 0x13, 0x32, 0x07,
12497 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
12498 0x08, 0x05, 0x06, 0x4d,
12499 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
12500 0x2d, 0x12, 0xfe, 0xe6,
12501 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
12502 0x02, 0x2b, 0xfe, 0x42,
12503 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12504 0xfe, 0x87, 0x80, 0xfe,
12505 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
12506 0x07, 0x19, 0xfe, 0x7c,
12507 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
12508 0x17, 0xfe, 0x90, 0x05,
12509 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
12510 0xa0, 0x00, 0x28, 0xfe,
12511 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
12512 0x34, 0xfe, 0x89, 0x48,
12513 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
12514 0x12, 0xfe, 0xe3, 0x00,
12515 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
12516 0x70, 0x05, 0x88, 0x25,
12517 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
12518 0x09, 0x48, 0xff, 0x02,
12519 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
12520 0x08, 0x53, 0x05, 0xcb,
12521 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
12522 0x05, 0x1b, 0xfe, 0x22,
12523 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
12524 0x0d, 0x00, 0x01, 0x36,
12525 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
12526 0x03, 0x5c, 0x28, 0xfe,
12527 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
12528 0x05, 0x1f, 0xfe, 0x02,
12529 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
12530 0x01, 0x4b, 0x12, 0xfe,
12531 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
12532 0x12, 0x03, 0x45, 0x28,
12533 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
12534 0x43, 0x48, 0xc4, 0xcc,
12535 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
12536 0x6e, 0x41, 0x01, 0xb2,
12537 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
12538 0xfe, 0xcc, 0x15, 0x1d,
12539 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
12540 0x45, 0xc1, 0x0c, 0x45,
12541 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
12542 0xe2, 0x00, 0x27, 0xdb,
12543 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
12544 0xfe, 0x06, 0xf0, 0xfe,
12545 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
12546 0x16, 0x19, 0x01, 0x0b,
12547 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
12548 0xfe, 0x99, 0xa4, 0x01,
12549 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
12550 0x12, 0x08, 0x05, 0x1a,
12551 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
12552 0x0b, 0x16, 0x00, 0x01,
12553 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
12554 0xe2, 0x6c, 0x58, 0xbe,
12555 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
12556 0xfe, 0x09, 0x6f, 0xba,
12557 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
12558 0xfe, 0x54, 0x07, 0x1c,
12559 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
12560 0x07, 0x02, 0x24, 0x01,
12561 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
12562 0x2c, 0x90, 0xfe, 0xae,
12563 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
12564 0x37, 0x22, 0x20, 0x07,
12565 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
12566 0xfe, 0x06, 0x10, 0xfe,
12567 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
12568 0x37, 0x01, 0xb3, 0xb8,
12569 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
12570 0x50, 0xfe, 0x44, 0x51,
12571 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
12572 0x14, 0x5f, 0xfe, 0x0c,
12573 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
12574 0x14, 0x3e, 0xfe, 0x4a,
12575 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
12576 0x90, 0x0c, 0x60, 0x14,
12577 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
12578 0xfe, 0x44, 0x90, 0xfe,
12579 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
12580 0x0c, 0x5e, 0x14, 0x5f,
12581 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
12582 0x14, 0x3c, 0x21, 0x0c,
12583 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
12584 0x27, 0xdd, 0xfe, 0x9e,
12585 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
12586 0x9a, 0x08, 0xc6, 0xfe,
12587 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
12588 0x95, 0x86, 0x02, 0x24,
12589 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
12590 0x06, 0xfe, 0x10, 0x12,
12591 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
12592 0x1c, 0x02, 0xfe, 0x18,
12593 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
12594 0x2c, 0x1c, 0xfe, 0xaa,
12595 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
12596 0xde, 0x09, 0xfe, 0xb7,
12597 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
12598 0xfe, 0xf1, 0x18, 0xfe,
12599 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
12600 0x14, 0x59, 0xfe, 0x95,
12601 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
12602 0xfe, 0xf0, 0x08, 0xb5,
12603 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
12604 0x0b, 0xb6, 0xfe, 0xbf,
12605 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
12606 0x12, 0xc2, 0xfe, 0xd2,
12607 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
12608 0x06, 0x17, 0x85, 0xc5,
12609 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
12610 0x9d, 0x01, 0x36, 0x10,
12611 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
12612 0x98, 0x80, 0xfe, 0x19,
12613 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
12614 0xfe, 0x44, 0x54, 0xbe,
12615 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
12616 0x02, 0x4a, 0x08, 0x05,
12617 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
12618 0x9c, 0x3c, 0xfe, 0x6c,
12619 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
12620 0x3b, 0x40, 0x03, 0x49,
12621 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
12622 0x8f, 0xfe, 0xe3, 0x54,
12623 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
12624 0xda, 0x09, 0xfe, 0x8b,
12625 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
12626 0x0a, 0x3a, 0x49, 0x3b,
12627 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
12628 0xad, 0xfe, 0x01, 0x59,
12629 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
12630 0x49, 0x8f, 0xfe, 0xe3,
12631 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
12632 0x4a, 0x3a, 0x49, 0x3b,
12633 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
12634 0x02, 0x4a, 0x08, 0x05,
12635 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
12636 0xb7, 0xfe, 0x03, 0xa1,
12637 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12638 0xfe, 0x86, 0x91, 0x6a,
12639 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12640 0x61, 0x0c, 0x7f, 0x14,
12641 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12642 0x9b, 0x2e, 0x9c, 0x3c,
12643 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12644 0xfa, 0x3c, 0x01, 0xef,
12645 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12646 0xe4, 0x08, 0x05, 0x1f,
12647 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12648 0x03, 0x5e, 0x29, 0x5f,
12649 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12650 0xf4, 0x09, 0x08, 0x05,
12651 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12652 0x81, 0x50, 0xfe, 0x10,
12653 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12654 0x08, 0x09, 0x12, 0xa6,
12655 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12656 0x08, 0x09, 0xfe, 0x0c,
12657 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12658 0x08, 0x05, 0x0a, 0xfe,
12659 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12660 0xf0, 0xe2, 0x15, 0x7e,
12661 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12662 0x57, 0x3d, 0xfe, 0xed,
12663 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12664 0x00, 0xff, 0x35, 0xfe,
12665 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12666 0x1e, 0x19, 0x8a, 0x03,
12667 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12668 0xfe, 0xd1, 0xf0, 0xfe,
12669 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12670 0x10, 0xfe, 0xce, 0xf0,
12671 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12672 0x10, 0xfe, 0x22, 0x00,
12673 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12674 0x02, 0x65, 0xfe, 0xd0,
12675 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12676 0x0b, 0x10, 0x58, 0xfe,
12677 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12678 0x12, 0x00, 0x2c, 0x0f,
12679 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12680 0x0c, 0xbc, 0x17, 0x34,
12681 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12682 0x0c, 0x1c, 0x34, 0x94,
12683 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12684 0x4b, 0xfe, 0xdb, 0x10,
12685 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12686 0x89, 0xf0, 0x24, 0x33,
12687 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12688 0x33, 0x31, 0xdf, 0xbc,
12689 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12690 0x17, 0xfe, 0x2c, 0x0d,
12691 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12692 0x12, 0x55, 0xfe, 0x28,
12693 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12694 0x44, 0xfe, 0x28, 0x00,
12695 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12696 0x0f, 0x64, 0x12, 0x2f,
12697 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12698 0x0a, 0xfe, 0xb4, 0x10,
12699 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12700 0xfe, 0x34, 0x46, 0xac,
12701 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12702 0x37, 0x01, 0xf5, 0x01,
12703 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12704 0xfe, 0x2e, 0x03, 0x08,
12705 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12706 0x1a, 0xfe, 0x58, 0x12,
12707 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12708 0xfe, 0x50, 0x0d, 0xfe,
12709 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12710 0xfe, 0xa9, 0x10, 0x10,
12711 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12712 0xfe, 0x13, 0x00, 0xfe,
12713 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12714 0x24, 0x00, 0x8c, 0xb5,
12715 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12716 0xfe, 0x9d, 0x41, 0xfe,
12717 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12718 0xb4, 0x15, 0xfe, 0x31,
12719 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12720 0xec, 0xd0, 0xfc, 0x44,
12721 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12722 0x4b, 0x91, 0xfe, 0x75,
12723 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12724 0x0e, 0xfe, 0x44, 0x48,
12725 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12726 0xfe, 0x41, 0x58, 0x09,
12727 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12728 0x2e, 0x03, 0x09, 0x5d,
12729 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12730 0xce, 0x47, 0xfe, 0xad,
12731 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12732 0x59, 0x13, 0x9f, 0x13,
12733 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12734 0xe0, 0x0e, 0x0f, 0x06,
12735 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12736 0x3a, 0x01, 0x56, 0xfe,
12737 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12738 0x20, 0x4f, 0xfe, 0x05,
12739 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12740 0x48, 0xf4, 0x0d, 0xfe,
12741 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12742 0x15, 0x1a, 0x39, 0xa0,
12743 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12744 0x0c, 0xfe, 0x60, 0x01,
12745 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12746 0x06, 0x13, 0x2f, 0x12,
12747 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12748 0x22, 0x9f, 0xb7, 0x13,
12749 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12750 0xa0, 0xb4, 0xfe, 0xd9,
12751 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12752 0xc3, 0xfe, 0x03, 0xdc,
12753 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12754 0xfe, 0x00, 0xcc, 0x04,
12755 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12756 0xfe, 0x1c, 0x80, 0x07,
12757 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12758 0xfe, 0x0c, 0x90, 0xfe,
12759 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12760 0x0a, 0xfe, 0x3c, 0x50,
12761 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12762 0x16, 0x08, 0x05, 0x1b,
12763 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12764 0xfe, 0x2c, 0x13, 0x01,
12765 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12766 0x0c, 0xfe, 0x64, 0x01,
12767 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12768 0x80, 0x8d, 0xfe, 0x01,
12769 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12770 0x22, 0x20, 0xfb, 0x79,
12771 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12772 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012773
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012774 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12775 0xb2, 0x00, 0xfe, 0x09,
12776 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12777 0x45, 0x0f, 0x46, 0x52,
12778 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12779 0x0f, 0x44, 0x11, 0x0f,
12780 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12781 0x25, 0x11, 0x13, 0x20,
12782 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12783 0x56, 0xfe, 0xd6, 0xf0,
12784 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12785 0x18, 0x1c, 0x04, 0x42,
12786 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12787 0xf5, 0x13, 0x04, 0x01,
12788 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12789 0x13, 0x32, 0x07, 0x2f,
12790 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12791 0x41, 0x48, 0xfe, 0x45,
12792 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12793 0x07, 0x11, 0xac, 0x09,
12794 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12795 0x82, 0x4e, 0xfe, 0x14,
12796 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12797 0xfe, 0x01, 0xec, 0xa2,
12798 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12799 0x2a, 0x01, 0xe3, 0xfe,
12800 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12801 0xfe, 0x48, 0x12, 0x07,
12802 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12803 0xfe, 0x32, 0x12, 0x07,
12804 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12805 0x1f, 0xfe, 0x12, 0x12,
12806 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12807 0x94, 0x4b, 0x04, 0x2d,
12808 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12809 0x32, 0x07, 0xa6, 0xfe,
12810 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12811 0x5a, 0xfe, 0x72, 0x12,
12812 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12813 0xfe, 0x26, 0x13, 0x03,
12814 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12815 0x0c, 0x7f, 0x0c, 0x80,
12816 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12817 0x3c, 0xfe, 0x04, 0x55,
12818 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12819 0x91, 0x10, 0x03, 0x3f,
12820 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12821 0x88, 0x9b, 0x2e, 0x9c,
12822 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12823 0x56, 0x0c, 0x5e, 0x14,
12824 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12825 0x03, 0x60, 0x29, 0x61,
12826 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12827 0x50, 0xfe, 0xc6, 0x50,
12828 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12829 0x29, 0x3e, 0xfe, 0x40,
12830 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12831 0x2d, 0x01, 0x0b, 0x1d,
12832 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12833 0x72, 0x01, 0xaf, 0x1e,
12834 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12835 0x0a, 0x55, 0x35, 0xfe,
12836 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12837 0x02, 0x72, 0xfe, 0x19,
12838 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12839 0x1d, 0xe8, 0x33, 0x31,
12840 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12841 0x0b, 0x1c, 0x34, 0x1d,
12842 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12843 0x33, 0x31, 0xfe, 0xe8,
12844 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12845 0x05, 0x1f, 0x35, 0xa9,
12846 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12847 0x14, 0x01, 0xaf, 0x8c,
12848 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12849 0x03, 0x45, 0x28, 0x35,
12850 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12851 0x03, 0x5c, 0xc1, 0x0c,
12852 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12853 0x89, 0x01, 0x0b, 0x1c,
12854 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12855 0xfe, 0x42, 0x58, 0xf1,
12856 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12857 0xf4, 0x06, 0xea, 0x32,
12858 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12859 0x01, 0x0b, 0x26, 0x89,
12860 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12861 0x26, 0xfe, 0xd4, 0x13,
12862 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12863 0x13, 0x1c, 0xfe, 0xd0,
12864 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12865 0x0f, 0x71, 0xff, 0x02,
12866 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12867 0x00, 0x5c, 0x04, 0x0f,
12868 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12869 0xfe, 0x00, 0x5c, 0x04,
12870 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12871 0x02, 0x00, 0x57, 0x52,
12872 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12873 0x87, 0x04, 0xfe, 0x03,
12874 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12875 0xfe, 0x00, 0x7d, 0xfe,
12876 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12877 0x14, 0x5f, 0x57, 0x3f,
12878 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12879 0x5a, 0x8d, 0x04, 0x01,
12880 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12881 0xfe, 0x96, 0x15, 0x33,
12882 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12883 0x0a, 0xfe, 0xc1, 0x59,
12884 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12885 0x21, 0x69, 0x1a, 0xee,
12886 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12887 0x30, 0xfe, 0x78, 0x10,
12888 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12889 0x98, 0xfe, 0x30, 0x00,
12890 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12891 0x98, 0xfe, 0x64, 0x00,
12892 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12893 0x10, 0x69, 0x06, 0xfe,
12894 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12895 0x18, 0x59, 0x0f, 0x06,
12896 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12897 0x43, 0xf4, 0x9f, 0xfe,
12898 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12899 0x9e, 0xfe, 0xf3, 0x10,
12900 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12901 0x17, 0xfe, 0x4d, 0xe4,
12902 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12903 0x17, 0xfe, 0x4d, 0xe4,
12904 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12905 0xf4, 0x00, 0xe9, 0x91,
12906 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12907 0x04, 0x16, 0x06, 0x01,
12908 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12909 0x0b, 0x26, 0xf3, 0x76,
12910 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12911 0x16, 0x19, 0x01, 0x0b,
12912 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12913 0x0b, 0x26, 0xb1, 0x76,
12914 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12915 0xfe, 0x48, 0x13, 0xb8,
12916 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12917 0xec, 0xfe, 0x27, 0x01,
12918 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12919 0x07, 0xfe, 0xe3, 0x00,
12920 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12921 0x22, 0xd4, 0x07, 0x06,
12922 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12923 0x07, 0x11, 0xae, 0x09,
12924 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12925 0x0e, 0x8e, 0xfe, 0x80,
12926 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12927 0x09, 0x48, 0x01, 0x0e,
12928 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12929 0x80, 0xfe, 0x80, 0x4c,
12930 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12931 0x09, 0x5d, 0x01, 0x87,
12932 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12933 0x19, 0xde, 0xfe, 0x24,
12934 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12935 0x17, 0xad, 0x9a, 0x1b,
12936 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12937 0x16, 0xfe, 0xda, 0x10,
12938 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12939 0x18, 0x58, 0x03, 0xfe,
12940 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12941 0xf4, 0x06, 0xfe, 0x3c,
12942 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12943 0x97, 0xfe, 0x38, 0x17,
12944 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12945 0x10, 0x18, 0x11, 0x75,
12946 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12947 0x2e, 0x97, 0xfe, 0x5a,
12948 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12949 0xfe, 0x98, 0xe7, 0x00,
12950 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12951 0xfe, 0x30, 0xbc, 0xfe,
12952 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12953 0xcb, 0x97, 0xfe, 0x92,
12954 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12955 0x42, 0x10, 0xfe, 0x02,
12956 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12957 0x03, 0xa1, 0xfe, 0x1d,
12958 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12959 0x9a, 0x5b, 0x41, 0xfe,
12960 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12961 0x11, 0x12, 0xfe, 0xdd,
12962 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12963 0x17, 0x15, 0x06, 0x39,
12964 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12965 0xfe, 0x7e, 0x18, 0x1e,
12966 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12967 0x12, 0xfe, 0xe1, 0x10,
12968 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12969 0x13, 0x42, 0x92, 0x09,
12970 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12971 0xf0, 0xfe, 0x00, 0xcc,
12972 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12973 0x0e, 0xfe, 0x80, 0x4c,
12974 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12975 0x24, 0x12, 0xfe, 0x14,
12976 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12977 0xe7, 0x0a, 0x10, 0xfe,
12978 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12979 0x08, 0x54, 0x1b, 0x37,
12980 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12981 0x90, 0x3a, 0xce, 0x3b,
12982 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
12983 0x13, 0xa3, 0x04, 0x09,
12984 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
12985 0x44, 0x17, 0xfe, 0xe8,
12986 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
12987 0x5d, 0x01, 0xa8, 0x09,
12988 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
12989 0x1c, 0x19, 0x03, 0xfe,
12990 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
12991 0x6b, 0xfe, 0x2e, 0x19,
12992 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
12993 0xfe, 0x0b, 0x00, 0x6b,
12994 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
12995 0x08, 0x10, 0x03, 0xfe,
12996 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
12997 0x04, 0x68, 0x54, 0xe7,
12998 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
12999 0x1a, 0xf4, 0xfe, 0x00,
13000 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
13001 0x04, 0x07, 0x7e, 0xfe,
13002 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
13003 0x07, 0x1a, 0xfe, 0x5a,
13004 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
13005 0x25, 0x6d, 0xe5, 0x07,
13006 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
13007 0xa9, 0xb8, 0x04, 0x15,
13008 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
13009 0x40, 0x5c, 0x04, 0x1c,
13010 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
13011 0xf7, 0xfe, 0x82, 0xf0,
13012 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013013};
13014
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013015static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
13016static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013017
13018/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013019static unsigned char _adv_asc38C1600_buf[] = {
13020 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
13021 0x18, 0xe4, 0x01, 0x00,
13022 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
13023 0x07, 0x17, 0xc0, 0x5f,
13024 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
13025 0x85, 0xf0, 0x86, 0xf0,
13026 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
13027 0x98, 0x57, 0x01, 0xe6,
13028 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
13029 0x38, 0x54, 0x32, 0xf0,
13030 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
13031 0x00, 0xe6, 0xb1, 0xf0,
13032 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
13033 0x06, 0x13, 0x0c, 0x1c,
13034 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
13035 0xb9, 0x54, 0x00, 0x80,
13036 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
13037 0x03, 0xe6, 0x01, 0xea,
13038 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
13039 0x04, 0x13, 0xbb, 0x55,
13040 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
13041 0xbb, 0x00, 0xc0, 0x00,
13042 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
13043 0x4c, 0x1c, 0x4e, 0x1c,
13044 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
13045 0x24, 0x01, 0x3c, 0x01,
13046 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
13047 0x78, 0x01, 0x7c, 0x01,
13048 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
13049 0x6e, 0x1e, 0x02, 0x48,
13050 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
13051 0x03, 0xfc, 0x06, 0x00,
13052 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
13053 0x30, 0x1c, 0x38, 0x1c,
13054 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
13055 0x5d, 0xf0, 0xa7, 0xf0,
13056 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
13057 0x33, 0x00, 0x34, 0x00,
13058 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
13059 0x79, 0x01, 0x3c, 0x09,
13060 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
13061 0x40, 0x16, 0x50, 0x16,
13062 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
13063 0x05, 0xf0, 0x09, 0xf0,
13064 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
13065 0x9c, 0x00, 0xa4, 0x00,
13066 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
13067 0xe9, 0x09, 0x5c, 0x0c,
13068 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
13069 0x42, 0x1d, 0x08, 0x44,
13070 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
13071 0x83, 0x55, 0x83, 0x59,
13072 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
13073 0x4b, 0xf4, 0x04, 0xf8,
13074 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
13075 0xa8, 0x00, 0xaa, 0x00,
13076 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
13077 0x7a, 0x01, 0x82, 0x01,
13078 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
13079 0x68, 0x08, 0x10, 0x0d,
13080 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
13081 0xf3, 0x10, 0x06, 0x12,
13082 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
13083 0xf0, 0x35, 0x05, 0xfe,
13084 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
13085 0xfe, 0x88, 0x01, 0xff,
13086 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
13087 0x00, 0xfe, 0x57, 0x24,
13088 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
13089 0x00, 0x00, 0xff, 0x08,
13090 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
13091 0xff, 0xff, 0xff, 0x13,
13092 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
13093 0xfe, 0x04, 0xf7, 0xe8,
13094 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
13095 0x0d, 0x51, 0x37, 0xfe,
13096 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
13097 0xfe, 0xf8, 0x01, 0xfe,
13098 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
13099 0x05, 0xfe, 0x08, 0x0f,
13100 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
13101 0x28, 0x1c, 0x03, 0xfe,
13102 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
13103 0x48, 0xf0, 0xfe, 0x90,
13104 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
13105 0x02, 0xfe, 0x46, 0xf0,
13106 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
13107 0xfe, 0x4e, 0x02, 0xfe,
13108 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
13109 0x0d, 0xa2, 0x1c, 0x07,
13110 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
13111 0x1c, 0xf5, 0xfe, 0x1e,
13112 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
13113 0xde, 0x0a, 0x81, 0x01,
13114 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
13115 0x81, 0x01, 0x5c, 0xfe,
13116 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
13117 0xfe, 0x58, 0x1c, 0x1c,
13118 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
13119 0x2b, 0xfe, 0x9e, 0x02,
13120 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
13121 0x00, 0x47, 0xb8, 0x01,
13122 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
13123 0x1a, 0x31, 0xfe, 0x69,
13124 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
13125 0x1e, 0x1e, 0x20, 0x2c,
13126 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
13127 0x44, 0x15, 0x56, 0x51,
13128 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
13129 0x01, 0x18, 0x09, 0x00,
13130 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
13131 0x18, 0xfe, 0xc8, 0x54,
13132 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
13133 0xfe, 0x02, 0xe8, 0x30,
13134 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
13135 0xfe, 0xe4, 0x01, 0xfe,
13136 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
13137 0x26, 0xf0, 0xfe, 0x66,
13138 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
13139 0xef, 0x10, 0xfe, 0x9f,
13140 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
13141 0x70, 0x37, 0xfe, 0x48,
13142 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
13143 0x21, 0xb9, 0xc7, 0x20,
13144 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
13145 0xe1, 0x2a, 0xeb, 0xfe,
13146 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
13147 0x15, 0xfe, 0xe4, 0x00,
13148 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
13149 0xfe, 0x06, 0xf0, 0xfe,
13150 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
13151 0x03, 0x81, 0x1e, 0x1b,
13152 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
13153 0xea, 0xfe, 0x46, 0x1c,
13154 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
13155 0xfe, 0x48, 0x1c, 0x75,
13156 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
13157 0xe1, 0x01, 0x18, 0x77,
13158 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
13159 0x8f, 0xfe, 0x70, 0x02,
13160 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
13161 0x16, 0xfe, 0x4a, 0x04,
13162 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
13163 0x02, 0x00, 0x10, 0x01,
13164 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
13165 0xee, 0xfe, 0x4c, 0x44,
13166 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
13167 0x7b, 0xec, 0x60, 0x8d,
13168 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
13169 0x0c, 0x06, 0x28, 0xfe,
13170 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
13171 0x13, 0x34, 0xfe, 0x4c,
13172 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
13173 0x13, 0x01, 0x0c, 0x06,
13174 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
13175 0x28, 0xf9, 0x1f, 0x7f,
13176 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
13177 0xfe, 0xa4, 0x0e, 0x05,
13178 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
13179 0x9c, 0x93, 0x3a, 0x0b,
13180 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
13181 0x7d, 0x1d, 0xfe, 0x46,
13182 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
13183 0xfe, 0x87, 0x83, 0xfe,
13184 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
13185 0x13, 0x0f, 0xfe, 0x20,
13186 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
13187 0x12, 0x01, 0x38, 0x06,
13188 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
13189 0x05, 0xd0, 0x54, 0x01,
13190 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
13191 0x50, 0x12, 0x5e, 0xff,
13192 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
13193 0x00, 0x10, 0x2f, 0xfe,
13194 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
13195 0x38, 0xfe, 0x4a, 0xf0,
13196 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
13197 0x21, 0x00, 0xf1, 0x2e,
13198 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
13199 0x10, 0x2f, 0xfe, 0xd0,
13200 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
13201 0x1c, 0x00, 0x4d, 0x01,
13202 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
13203 0x28, 0xfe, 0x24, 0x12,
13204 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
13205 0x0d, 0x00, 0x01, 0x42,
13206 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
13207 0x03, 0xb6, 0x1e, 0xfe,
13208 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
13209 0xfe, 0x72, 0x06, 0x0a,
13210 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
13211 0x19, 0x16, 0xfe, 0x68,
13212 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
13213 0x03, 0x9a, 0x1e, 0xfe,
13214 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
13215 0x48, 0xfe, 0x92, 0x06,
13216 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
13217 0x58, 0xff, 0x02, 0x00,
13218 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
13219 0xfe, 0xea, 0x06, 0x01,
13220 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
13221 0xfe, 0xe0, 0x06, 0x15,
13222 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
13223 0x01, 0x84, 0xfe, 0xae,
13224 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
13225 0x1e, 0xfe, 0x1a, 0x12,
13226 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
13227 0x43, 0x48, 0x62, 0x80,
13228 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
13229 0x36, 0xfe, 0x02, 0xf6,
13230 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
13231 0xd0, 0x0d, 0x17, 0xfe,
13232 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
13233 0x9e, 0x15, 0x82, 0x01,
13234 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
13235 0x57, 0x10, 0xe6, 0x05,
13236 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
13237 0xfe, 0x9c, 0x32, 0x5f,
13238 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
13239 0xfe, 0x0a, 0xf0, 0xfe,
13240 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
13241 0xaf, 0xa0, 0x05, 0x29,
13242 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
13243 0x00, 0x01, 0x08, 0x14,
13244 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
13245 0x14, 0x00, 0x05, 0xfe,
13246 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
13247 0x12, 0xfe, 0x30, 0x13,
13248 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
13249 0x01, 0x08, 0x14, 0x00,
13250 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
13251 0x78, 0x4f, 0x0f, 0xfe,
13252 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
13253 0x28, 0x48, 0xfe, 0x6c,
13254 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
13255 0x12, 0x53, 0x63, 0x4e,
13256 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
13257 0x6c, 0x08, 0xaf, 0xa0,
13258 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
13259 0x05, 0xed, 0xfe, 0x9c,
13260 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
13261 0x1e, 0xfe, 0x99, 0x58,
13262 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
13263 0x22, 0x6b, 0x01, 0x0c,
13264 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
13265 0x1e, 0x47, 0x2c, 0x7a,
13266 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
13267 0x01, 0x0c, 0x61, 0x65,
13268 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
13269 0x16, 0xfe, 0x08, 0x50,
13270 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
13271 0x01, 0xfe, 0xce, 0x1e,
13272 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
13273 0x01, 0xfe, 0xfe, 0x1e,
13274 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
13275 0x10, 0x01, 0x0c, 0x06,
13276 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
13277 0x10, 0x6a, 0x22, 0x6b,
13278 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
13279 0xfe, 0x9f, 0x83, 0x33,
13280 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
13281 0x3a, 0x0b, 0xfe, 0xc6,
13282 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
13283 0x01, 0xfe, 0xce, 0x1e,
13284 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
13285 0x04, 0xfe, 0xc0, 0x93,
13286 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
13287 0x10, 0x4b, 0x22, 0x4c,
13288 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
13289 0x4e, 0x11, 0x2f, 0xfe,
13290 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
13291 0x3c, 0x37, 0x88, 0xf5,
13292 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
13293 0xd3, 0xfe, 0x42, 0x0a,
13294 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
13295 0x05, 0x29, 0x01, 0x41,
13296 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
13297 0xfe, 0x14, 0x12, 0x01,
13298 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
13299 0x2e, 0x1c, 0x05, 0xfe,
13300 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
13301 0xfe, 0x2c, 0x1c, 0xfe,
13302 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
13303 0x92, 0x10, 0xc4, 0xf6,
13304 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
13305 0xe7, 0x10, 0xfe, 0x2b,
13306 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
13307 0xac, 0xfe, 0xd2, 0xf0,
13308 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
13309 0x1b, 0xbf, 0xd4, 0x5b,
13310 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
13311 0x5e, 0x32, 0x1f, 0x7f,
13312 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
13313 0x05, 0x70, 0xfe, 0x74,
13314 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
13315 0x0f, 0x4d, 0x01, 0xfe,
13316 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
13317 0x0d, 0x2b, 0xfe, 0xe2,
13318 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
13319 0xfe, 0x88, 0x13, 0x21,
13320 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
13321 0x83, 0x83, 0xfe, 0xc9,
13322 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
13323 0x91, 0x04, 0xfe, 0x84,
13324 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
13325 0xfe, 0xcb, 0x57, 0x0b,
13326 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
13327 0x6a, 0x3b, 0x6b, 0x10,
13328 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
13329 0x20, 0x6e, 0xdb, 0x64,
13330 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
13331 0xfe, 0x04, 0xfa, 0x64,
13332 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
13333 0x10, 0x98, 0x91, 0x6c,
13334 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
13335 0x4b, 0x7e, 0x4c, 0x01,
13336 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
13337 0x58, 0xfe, 0x91, 0x58,
13338 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
13339 0x1b, 0x40, 0x01, 0x0c,
13340 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
13341 0xfe, 0x10, 0x90, 0x04,
13342 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
13343 0x79, 0x0b, 0x0e, 0xfe,
13344 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
13345 0x01, 0x0c, 0x06, 0x0d,
13346 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
13347 0x0c, 0x58, 0xfe, 0x8d,
13348 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
13349 0x83, 0x33, 0x0b, 0x0e,
13350 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
13351 0x19, 0xfe, 0x19, 0x41,
13352 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
13353 0x19, 0xfe, 0x44, 0x00,
13354 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
13355 0x4c, 0xfe, 0x0c, 0x51,
13356 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
13357 0x76, 0x10, 0xac, 0xfe,
13358 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
13359 0xe3, 0x23, 0x07, 0xfe,
13360 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
13361 0xcc, 0x0c, 0x1f, 0x92,
13362 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
13363 0x0c, 0xfe, 0x3e, 0x10,
13364 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
13365 0xfe, 0xcb, 0xf0, 0xfe,
13366 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
13367 0xf4, 0x0c, 0x19, 0x94,
13368 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
13369 0xfe, 0xcc, 0xf0, 0xef,
13370 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
13371 0x4e, 0x11, 0x2f, 0xfe,
13372 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
13373 0x3c, 0x37, 0x88, 0xf5,
13374 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
13375 0x2f, 0xfe, 0x3e, 0x0d,
13376 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
13377 0xd2, 0x9f, 0xd3, 0x9f,
13378 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
13379 0xc5, 0x75, 0xd7, 0x99,
13380 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
13381 0x9c, 0x2f, 0xfe, 0x8c,
13382 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
13383 0x42, 0x00, 0x05, 0x70,
13384 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
13385 0x0d, 0xfe, 0x44, 0x13,
13386 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
13387 0xfe, 0xda, 0x0e, 0x0a,
13388 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
13389 0x10, 0x01, 0xfe, 0xf4,
13390 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
13391 0x15, 0x56, 0x01, 0x85,
13392 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
13393 0xcc, 0x10, 0x01, 0xa7,
13394 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
13395 0xfe, 0x99, 0x83, 0xfe,
13396 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
13397 0x43, 0x00, 0xfe, 0xa2,
13398 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
13399 0x00, 0x1d, 0x40, 0x15,
13400 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
13401 0xfe, 0x3a, 0x03, 0x01,
13402 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
13403 0x76, 0x06, 0x12, 0xfe,
13404 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
13405 0xfe, 0x9d, 0xf0, 0xfe,
13406 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
13407 0x0c, 0x61, 0x12, 0x44,
13408 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
13409 0xfe, 0x2e, 0x10, 0x19,
13410 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
13411 0xfe, 0x41, 0x00, 0xa2,
13412 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
13413 0xea, 0x4f, 0xfe, 0x04,
13414 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
13415 0x35, 0xfe, 0x12, 0x1c,
13416 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
13417 0xfe, 0xd4, 0x11, 0x05,
13418 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
13419 0xce, 0x45, 0x31, 0x51,
13420 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
13421 0x67, 0xfe, 0x98, 0x56,
13422 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
13423 0x0c, 0x06, 0x28, 0xfe,
13424 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
13425 0xfe, 0xfa, 0x14, 0xfe,
13426 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
13427 0xfe, 0xe0, 0x14, 0xfe,
13428 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
13429 0xfe, 0xad, 0x13, 0x05,
13430 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
13431 0xe7, 0xfe, 0x08, 0x1c,
13432 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
13433 0x48, 0x55, 0xa5, 0x3b,
13434 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
13435 0xf0, 0x1a, 0x03, 0xfe,
13436 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
13437 0xec, 0xe7, 0x53, 0x00,
13438 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
13439 0x01, 0xfe, 0x62, 0x1b,
13440 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
13441 0xea, 0xe7, 0x53, 0x92,
13442 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
13443 0xfe, 0x38, 0x01, 0x23,
13444 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
13445 0x01, 0x01, 0xfe, 0x1e,
13446 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
13447 0x26, 0x02, 0x21, 0x96,
13448 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
13449 0xc3, 0xfe, 0xe1, 0x10,
13450 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
13451 0xfe, 0x03, 0xdc, 0xfe,
13452 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
13453 0x00, 0xcc, 0x02, 0xfe,
13454 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
13455 0x0f, 0xfe, 0x1c, 0x80,
13456 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
13457 0x0f, 0xfe, 0x1e, 0x80,
13458 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
13459 0x1d, 0x80, 0x04, 0xfe,
13460 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
13461 0x1e, 0xac, 0xfe, 0x14,
13462 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
13463 0x1f, 0xfe, 0x30, 0xf4,
13464 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
13465 0x56, 0xfb, 0x01, 0xfe,
13466 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
13467 0xfe, 0x00, 0x1d, 0x15,
13468 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
13469 0x22, 0x1b, 0xfe, 0x1e,
13470 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
13471 0x96, 0x90, 0x04, 0xfe,
13472 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
13473 0x01, 0x01, 0x0c, 0x06,
13474 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
13475 0x0e, 0x77, 0xfe, 0x01,
13476 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
13477 0x21, 0x2c, 0xfe, 0x00,
13478 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
13479 0x06, 0x58, 0x03, 0xfe,
13480 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
13481 0x03, 0xfe, 0xb2, 0x00,
13482 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
13483 0x66, 0x10, 0x55, 0x10,
13484 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
13485 0x54, 0x2b, 0xfe, 0x88,
13486 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
13487 0x91, 0x54, 0x2b, 0xfe,
13488 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
13489 0x00, 0x40, 0x8d, 0x2c,
13490 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
13491 0x12, 0x1c, 0x75, 0xfe,
13492 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
13493 0x14, 0xfe, 0x0e, 0x47,
13494 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
13495 0xa7, 0x90, 0x34, 0x60,
13496 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
13497 0x09, 0x56, 0xfe, 0x34,
13498 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
13499 0xfe, 0x45, 0x48, 0x01,
13500 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
13501 0x09, 0x1a, 0xa5, 0x0a,
13502 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
13503 0xfe, 0x14, 0x56, 0xfe,
13504 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
13505 0xec, 0xb8, 0xfe, 0x9e,
13506 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
13507 0xf4, 0xfe, 0xdd, 0x10,
13508 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
13509 0x12, 0x09, 0x0d, 0xfe,
13510 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
13511 0x13, 0x09, 0xfe, 0x23,
13512 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
13513 0x24, 0xfe, 0x12, 0x12,
13514 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
13515 0xae, 0x41, 0x02, 0x32,
13516 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
13517 0x35, 0x32, 0x01, 0x43,
13518 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
13519 0x13, 0x01, 0x0c, 0x06,
13520 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
13521 0xe5, 0x55, 0xb0, 0xfe,
13522 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
13523 0xfe, 0xb6, 0x0e, 0x10,
13524 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
13525 0x88, 0x20, 0x6e, 0x01,
13526 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
13527 0x55, 0xfe, 0x04, 0xfa,
13528 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
13529 0xfe, 0x40, 0x56, 0xfe,
13530 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
13531 0x44, 0x55, 0xfe, 0xe5,
13532 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
13533 0x68, 0x22, 0x69, 0x01,
13534 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
13535 0x6b, 0xfe, 0x2c, 0x50,
13536 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
13537 0x50, 0x03, 0x68, 0x3b,
13538 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
13539 0x40, 0x50, 0xfe, 0xc2,
13540 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
13541 0x16, 0x3d, 0x27, 0x25,
13542 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
13543 0xa6, 0x23, 0x3f, 0x1b,
13544 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
13545 0xfe, 0x0a, 0x55, 0x31,
13546 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
13547 0x51, 0x05, 0x72, 0x01,
13548 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
13549 0x2a, 0x3c, 0x16, 0xc0,
13550 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
13551 0xfe, 0x66, 0x15, 0x05,
13552 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
13553 0x2b, 0x3d, 0x01, 0x08,
13554 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
13555 0xb6, 0x1e, 0x83, 0x01,
13556 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
13557 0x07, 0x90, 0x3f, 0x01,
13558 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
13559 0x01, 0x43, 0x09, 0x82,
13560 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
13561 0x05, 0x72, 0xfe, 0xc0,
13562 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
13563 0x32, 0x01, 0x08, 0x17,
13564 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
13565 0x3d, 0x27, 0x25, 0xbd,
13566 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
13567 0xe8, 0x14, 0x01, 0xa6,
13568 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
13569 0x0e, 0x12, 0x01, 0x43,
13570 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
13571 0x01, 0x08, 0x17, 0x73,
13572 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
13573 0x27, 0x25, 0xbd, 0x09,
13574 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
13575 0xb6, 0x14, 0x86, 0xa8,
13576 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
13577 0x82, 0x4e, 0x05, 0x72,
13578 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
13579 0xfe, 0xc0, 0x19, 0x05,
13580 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
13581 0xcc, 0x01, 0x08, 0x26,
13582 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
13583 0xcc, 0x15, 0x5e, 0x32,
13584 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
13585 0xad, 0x23, 0xfe, 0xff,
13586 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
13587 0x00, 0x57, 0x52, 0xad,
13588 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
13589 0x02, 0x00, 0x57, 0x52,
13590 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
13591 0x02, 0x13, 0x58, 0xff,
13592 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
13593 0x5c, 0x0a, 0x55, 0x01,
13594 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
13595 0xff, 0x03, 0x00, 0x54,
13596 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
13597 0x7c, 0x3a, 0x0b, 0x0e,
13598 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
13599 0xfe, 0x1a, 0xf7, 0x00,
13600 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
13601 0xda, 0x6d, 0x02, 0xfe,
13602 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
13603 0x02, 0x01, 0xc6, 0xfe,
13604 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
13605 0x25, 0xbe, 0x01, 0x08,
13606 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
13607 0x03, 0x9a, 0x1e, 0xfe,
13608 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
13609 0x48, 0xfe, 0x08, 0x17,
13610 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
13611 0x17, 0x4d, 0x13, 0x07,
13612 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
13613 0xff, 0x02, 0x83, 0x55,
13614 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
13615 0x17, 0x1c, 0x63, 0x13,
13616 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
13617 0x00, 0xb0, 0xfe, 0x80,
13618 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
13619 0x53, 0x07, 0xfe, 0x60,
13620 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
13621 0x00, 0x1c, 0x95, 0x13,
13622 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
13623 0xfe, 0x43, 0xf4, 0x96,
13624 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
13625 0xf4, 0x94, 0xf6, 0x8b,
13626 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
13627 0xda, 0x17, 0x62, 0x49,
13628 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
13629 0x71, 0x50, 0x26, 0xfe,
13630 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
13631 0x58, 0x02, 0x50, 0x13,
13632 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
13633 0x25, 0xbe, 0xfe, 0x03,
13634 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
13635 0x0a, 0x01, 0x08, 0x16,
13636 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13637 0x01, 0x08, 0x16, 0xa9,
13638 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13639 0x08, 0x16, 0xa9, 0x27,
13640 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13641 0x01, 0x38, 0x06, 0x24,
13642 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13643 0x78, 0x03, 0x9a, 0x1e,
13644 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13645 0xfe, 0x40, 0x5a, 0x23,
13646 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13647 0x80, 0x48, 0xfe, 0xaa,
13648 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13649 0xfe, 0xac, 0x1d, 0xfe,
13650 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13651 0x43, 0x48, 0x2d, 0x93,
13652 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13653 0x36, 0xfe, 0x34, 0xf4,
13654 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13655 0x28, 0x10, 0xfe, 0xc0,
13656 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13657 0x18, 0x45, 0xfe, 0x1c,
13658 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13659 0x19, 0xfe, 0x04, 0xf4,
13660 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13661 0x21, 0xfe, 0x7f, 0x01,
13662 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13663 0x7e, 0x01, 0xfe, 0xc8,
13664 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13665 0x21, 0xfe, 0x81, 0x01,
13666 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13667 0x13, 0x0d, 0x02, 0x14,
13668 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13669 0xfe, 0x82, 0x19, 0x14,
13670 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13671 0x08, 0x02, 0x14, 0x07,
13672 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13673 0x01, 0x08, 0x17, 0xc1,
13674 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13675 0x08, 0x02, 0x50, 0x02,
13676 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13677 0x14, 0x12, 0x01, 0x08,
13678 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13679 0x08, 0x17, 0x74, 0xfe,
13680 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13681 0x74, 0x5f, 0xcc, 0x01,
13682 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13683 0xfe, 0x49, 0xf4, 0x00,
13684 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13685 0x02, 0x00, 0x10, 0x2f,
13686 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13687 0x16, 0xfe, 0x64, 0x1a,
13688 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13689 0x61, 0x07, 0x44, 0x02,
13690 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13691 0x13, 0x0a, 0x9d, 0x01,
13692 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13693 0xfe, 0x80, 0xe7, 0x1a,
13694 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13695 0x0a, 0x5a, 0x01, 0x18,
13696 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13697 0x7e, 0x1e, 0xfe, 0x80,
13698 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13699 0xfe, 0x80, 0x4c, 0x0a,
13700 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13701 0xfe, 0x19, 0xde, 0xfe,
13702 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13703 0x2a, 0x1c, 0xfa, 0xb3,
13704 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13705 0xf4, 0x1a, 0xfe, 0xfa,
13706 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13707 0xfe, 0x18, 0x58, 0x03,
13708 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13709 0xfe, 0x30, 0xf4, 0x07,
13710 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13711 0xf7, 0x24, 0xb1, 0xfe,
13712 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13713 0xfe, 0xba, 0x10, 0x1c,
13714 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13715 0x1d, 0xf7, 0x54, 0xb1,
13716 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13717 0xaf, 0x19, 0xfe, 0x98,
13718 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13719 0x1a, 0x87, 0x8b, 0x0f,
13720 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13721 0xfe, 0x32, 0x90, 0x04,
13722 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13723 0x7c, 0x12, 0xfe, 0x0f,
13724 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13725 0x31, 0x02, 0xc9, 0x2b,
13726 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13727 0x6a, 0xfe, 0x19, 0xfe,
13728 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13729 0x1b, 0xfe, 0x36, 0x14,
13730 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13731 0xfe, 0x80, 0xe7, 0x1a,
13732 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13733 0x30, 0xfe, 0x12, 0x45,
13734 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13735 0x39, 0xf0, 0x75, 0x26,
13736 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13737 0xe3, 0x23, 0x07, 0xfe,
13738 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13739 0x56, 0xfe, 0x3c, 0x13,
13740 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13741 0x01, 0x18, 0xcb, 0xfe,
13742 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13743 0xfe, 0x00, 0xcc, 0xcb,
13744 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13745 0xfe, 0x80, 0x4c, 0x01,
13746 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13747 0x12, 0xfe, 0x14, 0x56,
13748 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13749 0x0d, 0x19, 0xfe, 0x15,
13750 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13751 0x83, 0xfe, 0x18, 0x80,
13752 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13753 0x90, 0xfe, 0xba, 0x90,
13754 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13755 0x21, 0xb9, 0x88, 0x20,
13756 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13757 0x18, 0xfe, 0x49, 0x44,
13758 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13759 0x1a, 0xa4, 0x0a, 0x67,
13760 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13761 0x1d, 0x7b, 0xfe, 0x52,
13762 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13763 0x4e, 0xe4, 0xdd, 0x7b,
13764 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13765 0xfe, 0x4e, 0xe4, 0xfe,
13766 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13767 0xfe, 0x08, 0x10, 0x03,
13768 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13769 0x68, 0x54, 0xfe, 0xf1,
13770 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13771 0xfe, 0x1a, 0xf4, 0xfe,
13772 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13773 0x09, 0x92, 0xfe, 0x5a,
13774 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13775 0x5a, 0xf0, 0xfe, 0xc8,
13776 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13777 0x1a, 0x10, 0x09, 0x0d,
13778 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13779 0x1f, 0x93, 0x01, 0x42,
13780 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13781 0xfe, 0x14, 0xf0, 0x08,
13782 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13783 0xfe, 0x82, 0xf0, 0xfe,
13784 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13785 0x02, 0x0f, 0xfe, 0x18,
13786 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13787 0x80, 0x04, 0xfe, 0x82,
13788 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13789 0x83, 0x33, 0x0b, 0x0e,
13790 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13791 0x02, 0x0f, 0xfe, 0x04,
13792 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13793 0x80, 0x04, 0xfe, 0x80,
13794 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13795 0xfe, 0x99, 0x83, 0xfe,
13796 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13797 0x83, 0xfe, 0xce, 0x47,
13798 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13799 0x0b, 0x0e, 0x02, 0x0f,
13800 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13801 0xfe, 0x08, 0x90, 0x04,
13802 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13803 0xfe, 0x8a, 0x93, 0x79,
13804 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13805 0x0b, 0x0e, 0x02, 0x0f,
13806 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13807 0xfe, 0x3c, 0x90, 0x04,
13808 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13809 0x04, 0xfe, 0x83, 0x83,
13810 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013811};
13812
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013813static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13814static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013815
13816/* a_init.c */
13817/*
13818 * EEPROM Configuration.
13819 *
13820 * All drivers should use this structure to set the default EEPROM
13821 * configuration. The BIOS now uses this structure when it is built.
13822 * Additional structure information can be found in a_condor.h where
13823 * the structure is defined.
13824 *
13825 * The *_Field_IsChar structs are needed to correct for endianness.
13826 * These values are read from the board 16 bits at a time directly
13827 * into the structs. Because some fields are char, the values will be
13828 * in the wrong order. The *_Field_IsChar tells when to flip the
13829 * bytes. Data read and written to PCI memory is automatically swapped
13830 * on big-endian platforms so char fields read as words are actually being
13831 * unswapped on big-endian platforms.
13832 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013833static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = {
13834 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13835 0x0000, /* cfg_msw */
13836 0xFFFF, /* disc_enable */
13837 0xFFFF, /* wdtr_able */
13838 0xFFFF, /* sdtr_able */
13839 0xFFFF, /* start_motor */
13840 0xFFFF, /* tagqng_able */
13841 0xFFFF, /* bios_scan */
13842 0, /* scam_tolerant */
13843 7, /* adapter_scsi_id */
13844 0, /* bios_boot_delay */
13845 3, /* scsi_reset_delay */
13846 0, /* bios_id_lun */
13847 0, /* termination */
13848 0, /* reserved1 */
13849 0xFFE7, /* bios_ctrl */
13850 0xFFFF, /* ultra_able */
13851 0, /* reserved2 */
13852 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13853 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13854 0, /* dvc_cntl */
13855 0, /* bug_fix */
13856 0, /* serial_number_word1 */
13857 0, /* serial_number_word2 */
13858 0, /* serial_number_word3 */
13859 0, /* check_sum */
13860 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13861 , /* oem_name[16] */
13862 0, /* dvc_err_code */
13863 0, /* adv_err_code */
13864 0, /* adv_err_addr */
13865 0, /* saved_dvc_err_code */
13866 0, /* saved_adv_err_code */
13867 0, /* saved_adv_err_addr */
13868 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013869};
13870
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013871static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = {
13872 0, /* cfg_lsw */
13873 0, /* cfg_msw */
13874 0, /* -disc_enable */
13875 0, /* wdtr_able */
13876 0, /* sdtr_able */
13877 0, /* start_motor */
13878 0, /* tagqng_able */
13879 0, /* bios_scan */
13880 0, /* scam_tolerant */
13881 1, /* adapter_scsi_id */
13882 1, /* bios_boot_delay */
13883 1, /* scsi_reset_delay */
13884 1, /* bios_id_lun */
13885 1, /* termination */
13886 1, /* reserved1 */
13887 0, /* bios_ctrl */
13888 0, /* ultra_able */
13889 0, /* reserved2 */
13890 1, /* max_host_qng */
13891 1, /* max_dvc_qng */
13892 0, /* dvc_cntl */
13893 0, /* bug_fix */
13894 0, /* serial_number_word1 */
13895 0, /* serial_number_word2 */
13896 0, /* serial_number_word3 */
13897 0, /* check_sum */
13898 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13899 , /* oem_name[16] */
13900 0, /* dvc_err_code */
13901 0, /* adv_err_code */
13902 0, /* adv_err_addr */
13903 0, /* saved_dvc_err_code */
13904 0, /* saved_adv_err_code */
13905 0, /* saved_adv_err_addr */
13906 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013907};
13908
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013909static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = {
13910 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13911 0x0000, /* 01 cfg_msw */
13912 0xFFFF, /* 02 disc_enable */
13913 0xFFFF, /* 03 wdtr_able */
13914 0x4444, /* 04 sdtr_speed1 */
13915 0xFFFF, /* 05 start_motor */
13916 0xFFFF, /* 06 tagqng_able */
13917 0xFFFF, /* 07 bios_scan */
13918 0, /* 08 scam_tolerant */
13919 7, /* 09 adapter_scsi_id */
13920 0, /* bios_boot_delay */
13921 3, /* 10 scsi_reset_delay */
13922 0, /* bios_id_lun */
13923 0, /* 11 termination_se */
13924 0, /* termination_lvd */
13925 0xFFE7, /* 12 bios_ctrl */
13926 0x4444, /* 13 sdtr_speed2 */
13927 0x4444, /* 14 sdtr_speed3 */
13928 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13929 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13930 0, /* 16 dvc_cntl */
13931 0x4444, /* 17 sdtr_speed4 */
13932 0, /* 18 serial_number_word1 */
13933 0, /* 19 serial_number_word2 */
13934 0, /* 20 serial_number_word3 */
13935 0, /* 21 check_sum */
13936 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13937 , /* 22-29 oem_name[16] */
13938 0, /* 30 dvc_err_code */
13939 0, /* 31 adv_err_code */
13940 0, /* 32 adv_err_addr */
13941 0, /* 33 saved_dvc_err_code */
13942 0, /* 34 saved_adv_err_code */
13943 0, /* 35 saved_adv_err_addr */
13944 0, /* 36 reserved */
13945 0, /* 37 reserved */
13946 0, /* 38 reserved */
13947 0, /* 39 reserved */
13948 0, /* 40 reserved */
13949 0, /* 41 reserved */
13950 0, /* 42 reserved */
13951 0, /* 43 reserved */
13952 0, /* 44 reserved */
13953 0, /* 45 reserved */
13954 0, /* 46 reserved */
13955 0, /* 47 reserved */
13956 0, /* 48 reserved */
13957 0, /* 49 reserved */
13958 0, /* 50 reserved */
13959 0, /* 51 reserved */
13960 0, /* 52 reserved */
13961 0, /* 53 reserved */
13962 0, /* 54 reserved */
13963 0, /* 55 reserved */
13964 0, /* 56 cisptr_lsw */
13965 0, /* 57 cisprt_msw */
13966 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13967 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13968 0, /* 60 reserved */
13969 0, /* 61 reserved */
13970 0, /* 62 reserved */
13971 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013972};
13973
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013974static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = {
13975 0, /* 00 cfg_lsw */
13976 0, /* 01 cfg_msw */
13977 0, /* 02 disc_enable */
13978 0, /* 03 wdtr_able */
13979 0, /* 04 sdtr_speed1 */
13980 0, /* 05 start_motor */
13981 0, /* 06 tagqng_able */
13982 0, /* 07 bios_scan */
13983 0, /* 08 scam_tolerant */
13984 1, /* 09 adapter_scsi_id */
13985 1, /* bios_boot_delay */
13986 1, /* 10 scsi_reset_delay */
13987 1, /* bios_id_lun */
13988 1, /* 11 termination_se */
13989 1, /* termination_lvd */
13990 0, /* 12 bios_ctrl */
13991 0, /* 13 sdtr_speed2 */
13992 0, /* 14 sdtr_speed3 */
13993 1, /* 15 max_host_qng */
13994 1, /* max_dvc_qng */
13995 0, /* 16 dvc_cntl */
13996 0, /* 17 sdtr_speed4 */
13997 0, /* 18 serial_number_word1 */
13998 0, /* 19 serial_number_word2 */
13999 0, /* 20 serial_number_word3 */
14000 0, /* 21 check_sum */
14001 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
14002 , /* 22-29 oem_name[16] */
14003 0, /* 30 dvc_err_code */
14004 0, /* 31 adv_err_code */
14005 0, /* 32 adv_err_addr */
14006 0, /* 33 saved_dvc_err_code */
14007 0, /* 34 saved_adv_err_code */
14008 0, /* 35 saved_adv_err_addr */
14009 0, /* 36 reserved */
14010 0, /* 37 reserved */
14011 0, /* 38 reserved */
14012 0, /* 39 reserved */
14013 0, /* 40 reserved */
14014 0, /* 41 reserved */
14015 0, /* 42 reserved */
14016 0, /* 43 reserved */
14017 0, /* 44 reserved */
14018 0, /* 45 reserved */
14019 0, /* 46 reserved */
14020 0, /* 47 reserved */
14021 0, /* 48 reserved */
14022 0, /* 49 reserved */
14023 0, /* 50 reserved */
14024 0, /* 51 reserved */
14025 0, /* 52 reserved */
14026 0, /* 53 reserved */
14027 0, /* 54 reserved */
14028 0, /* 55 reserved */
14029 0, /* 56 cisptr_lsw */
14030 0, /* 57 cisprt_msw */
14031 0, /* 58 subsysvid */
14032 0, /* 59 subsysid */
14033 0, /* 60 reserved */
14034 0, /* 61 reserved */
14035 0, /* 62 reserved */
14036 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014037};
14038
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014039static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = {
14040 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
14041 0x0000, /* 01 cfg_msw */
14042 0xFFFF, /* 02 disc_enable */
14043 0xFFFF, /* 03 wdtr_able */
14044 0x5555, /* 04 sdtr_speed1 */
14045 0xFFFF, /* 05 start_motor */
14046 0xFFFF, /* 06 tagqng_able */
14047 0xFFFF, /* 07 bios_scan */
14048 0, /* 08 scam_tolerant */
14049 7, /* 09 adapter_scsi_id */
14050 0, /* bios_boot_delay */
14051 3, /* 10 scsi_reset_delay */
14052 0, /* bios_id_lun */
14053 0, /* 11 termination_se */
14054 0, /* termination_lvd */
14055 0xFFE7, /* 12 bios_ctrl */
14056 0x5555, /* 13 sdtr_speed2 */
14057 0x5555, /* 14 sdtr_speed3 */
14058 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
14059 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
14060 0, /* 16 dvc_cntl */
14061 0x5555, /* 17 sdtr_speed4 */
14062 0, /* 18 serial_number_word1 */
14063 0, /* 19 serial_number_word2 */
14064 0, /* 20 serial_number_word3 */
14065 0, /* 21 check_sum */
14066 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
14067 , /* 22-29 oem_name[16] */
14068 0, /* 30 dvc_err_code */
14069 0, /* 31 adv_err_code */
14070 0, /* 32 adv_err_addr */
14071 0, /* 33 saved_dvc_err_code */
14072 0, /* 34 saved_adv_err_code */
14073 0, /* 35 saved_adv_err_addr */
14074 0, /* 36 reserved */
14075 0, /* 37 reserved */
14076 0, /* 38 reserved */
14077 0, /* 39 reserved */
14078 0, /* 40 reserved */
14079 0, /* 41 reserved */
14080 0, /* 42 reserved */
14081 0, /* 43 reserved */
14082 0, /* 44 reserved */
14083 0, /* 45 reserved */
14084 0, /* 46 reserved */
14085 0, /* 47 reserved */
14086 0, /* 48 reserved */
14087 0, /* 49 reserved */
14088 0, /* 50 reserved */
14089 0, /* 51 reserved */
14090 0, /* 52 reserved */
14091 0, /* 53 reserved */
14092 0, /* 54 reserved */
14093 0, /* 55 reserved */
14094 0, /* 56 cisptr_lsw */
14095 0, /* 57 cisprt_msw */
14096 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
14097 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
14098 0, /* 60 reserved */
14099 0, /* 61 reserved */
14100 0, /* 62 reserved */
14101 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014102};
14103
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014104static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = {
14105 0, /* 00 cfg_lsw */
14106 0, /* 01 cfg_msw */
14107 0, /* 02 disc_enable */
14108 0, /* 03 wdtr_able */
14109 0, /* 04 sdtr_speed1 */
14110 0, /* 05 start_motor */
14111 0, /* 06 tagqng_able */
14112 0, /* 07 bios_scan */
14113 0, /* 08 scam_tolerant */
14114 1, /* 09 adapter_scsi_id */
14115 1, /* bios_boot_delay */
14116 1, /* 10 scsi_reset_delay */
14117 1, /* bios_id_lun */
14118 1, /* 11 termination_se */
14119 1, /* termination_lvd */
14120 0, /* 12 bios_ctrl */
14121 0, /* 13 sdtr_speed2 */
14122 0, /* 14 sdtr_speed3 */
14123 1, /* 15 max_host_qng */
14124 1, /* max_dvc_qng */
14125 0, /* 16 dvc_cntl */
14126 0, /* 17 sdtr_speed4 */
14127 0, /* 18 serial_number_word1 */
14128 0, /* 19 serial_number_word2 */
14129 0, /* 20 serial_number_word3 */
14130 0, /* 21 check_sum */
14131 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
14132 , /* 22-29 oem_name[16] */
14133 0, /* 30 dvc_err_code */
14134 0, /* 31 adv_err_code */
14135 0, /* 32 adv_err_addr */
14136 0, /* 33 saved_dvc_err_code */
14137 0, /* 34 saved_adv_err_code */
14138 0, /* 35 saved_adv_err_addr */
14139 0, /* 36 reserved */
14140 0, /* 37 reserved */
14141 0, /* 38 reserved */
14142 0, /* 39 reserved */
14143 0, /* 40 reserved */
14144 0, /* 41 reserved */
14145 0, /* 42 reserved */
14146 0, /* 43 reserved */
14147 0, /* 44 reserved */
14148 0, /* 45 reserved */
14149 0, /* 46 reserved */
14150 0, /* 47 reserved */
14151 0, /* 48 reserved */
14152 0, /* 49 reserved */
14153 0, /* 50 reserved */
14154 0, /* 51 reserved */
14155 0, /* 52 reserved */
14156 0, /* 53 reserved */
14157 0, /* 54 reserved */
14158 0, /* 55 reserved */
14159 0, /* 56 cisptr_lsw */
14160 0, /* 57 cisprt_msw */
14161 0, /* 58 subsysvid */
14162 0, /* 59 subsysid */
14163 0, /* 60 reserved */
14164 0, /* 61 reserved */
14165 0, /* 62 reserved */
14166 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014167};
14168
14169/*
14170 * Initialize the ADV_DVC_VAR structure.
14171 *
14172 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14173 *
14174 * For a non-fatal error return a warning code. If there are no warnings
14175 * then 0 is returned.
14176 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014177static int __init AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014178{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014179 ushort warn_code;
14180 AdvPortAddr iop_base;
14181 uchar pci_cmd_reg;
14182 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014183
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014184 warn_code = 0;
14185 asc_dvc->err_code = 0;
14186 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014187
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014188 /*
14189 * PCI Command Register
14190 *
14191 * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
14192 * I/O Space Control, Memory Space Control and Bus Master Control bits.
14193 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014194
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014195 if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
14196 AscPCIConfigCommandRegister))
14197 & AscPCICmdRegBits_BusMastering)
14198 != AscPCICmdRegBits_BusMastering) {
14199 pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014200
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014201 DvcAdvWritePCIConfigByte(asc_dvc,
14202 AscPCIConfigCommandRegister,
14203 pci_cmd_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014204
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014205 if (((DvcAdvReadPCIConfigByte
14206 (asc_dvc, AscPCIConfigCommandRegister))
14207 & AscPCICmdRegBits_BusMastering)
14208 != AscPCICmdRegBits_BusMastering) {
14209 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
14210 }
14211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014212
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014213 /*
14214 * PCI Latency Timer
14215 *
14216 * If the "latency timer" register is 0x20 or above, then we don't need
14217 * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
14218 * comes up less than 0x20).
14219 */
14220 if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
14221 DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer,
14222 0x20);
14223 if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) <
14224 0x20) {
14225 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
14226 }
14227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014228
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014229 /*
14230 * Save the state of the PCI Configuration Command Register
14231 * "Parity Error Response Control" Bit. If the bit is clear (0),
14232 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
14233 * DMA parity errors.
14234 */
14235 asc_dvc->cfg->control_flag = 0;
14236 if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
14237 & AscPCICmdRegBits_ParErrRespCtrl)) == 0) {
14238 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
14239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014240
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014241 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
14242 ADV_LIB_VERSION_MINOR;
14243 asc_dvc->cfg->chip_version =
14244 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014245
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014246 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
14247 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
14248 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014249
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014250 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
14251 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
14252 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014253
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014254 /*
14255 * Reset the chip to start and allow register writes.
14256 */
14257 if (AdvFindSignature(iop_base) == 0) {
14258 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
14259 return ADV_ERROR;
14260 } else {
14261 /*
14262 * The caller must set 'chip_type' to a valid setting.
14263 */
14264 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
14265 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
14266 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
14267 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
14268 return ADV_ERROR;
14269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014270
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014271 /*
14272 * Reset Chip.
14273 */
14274 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
14275 ADV_CTRL_REG_CMD_RESET);
14276 DvcSleepMilliSecond(100);
14277 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
14278 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014279
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014280 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14281 if ((status =
14282 AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) {
14283 return ADV_ERROR;
14284 }
14285 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
14286 if ((status =
14287 AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) {
14288 return ADV_ERROR;
14289 }
14290 } else {
14291 if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR) {
14292 return ADV_ERROR;
14293 }
14294 }
14295 warn_code |= status;
14296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014297
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014298 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014299}
14300
14301/*
14302 * Initialize the ASC-3550.
14303 *
14304 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14305 *
14306 * For a non-fatal error return a warning code. If there are no warnings
14307 * then 0 is returned.
14308 *
14309 * Needed after initialization for error recovery.
14310 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014311static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014312{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014313 AdvPortAddr iop_base;
14314 ushort warn_code;
14315 ADV_DCNT sum;
14316 int begin_addr;
14317 int end_addr;
14318 ushort code_sum;
14319 int word;
14320 int j;
14321 int adv_asc3550_expanded_size;
14322 ADV_CARR_T *carrp;
14323 ADV_DCNT contig_len;
14324 ADV_SDCNT buf_size;
14325 ADV_PADDR carr_paddr;
14326 int i;
14327 ushort scsi_cfg1;
14328 uchar tid;
14329 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14330 ushort wdtr_able = 0, sdtr_able, tagqng_able;
14331 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014332
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014333 /* If there is already an error, don't continue. */
14334 if (asc_dvc->err_code != 0) {
14335 return ADV_ERROR;
14336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014337
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014338 /*
14339 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
14340 */
14341 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
14342 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
14343 return ADV_ERROR;
14344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014345
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014346 warn_code = 0;
14347 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014348
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014349 /*
14350 * Save the RISC memory BIOS region before writing the microcode.
14351 * The BIOS may already be loaded and using its RISC LRAM region
14352 * so its region must be saved and restored.
14353 *
14354 * Note: This code makes the assumption, which is currently true,
14355 * that a chip reset does not clear RISC LRAM.
14356 */
14357 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14358 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14359 bios_mem[i]);
14360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014361
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014362 /*
14363 * Save current per TID negotiated values.
14364 */
14365 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
14366 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014367
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014368 bios_version =
14369 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
14370 major = (bios_version >> 12) & 0xF;
14371 minor = (bios_version >> 8) & 0xF;
14372 if (major < 3 || (major == 3 && minor == 1)) {
14373 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
14374 AdvReadWordLram(iop_base, 0x120, wdtr_able);
14375 } else {
14376 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14377 }
14378 }
14379 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14380 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14381 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14382 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14383 max_cmd[tid]);
14384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014386 /*
14387 * Load the Microcode
14388 *
14389 * Write the microcode image to RISC memory starting at address 0.
14390 */
14391 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
14392 /* Assume the following compressed format of the microcode buffer:
14393 *
14394 * 254 word (508 byte) table indexed by byte code followed
14395 * by the following byte codes:
14396 *
14397 * 1-Byte Code:
14398 * 00: Emit word 0 in table.
14399 * 01: Emit word 1 in table.
14400 * .
14401 * FD: Emit word 253 in table.
14402 *
14403 * Multi-Byte Code:
14404 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14405 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14406 */
14407 word = 0;
14408 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
14409 if (_adv_asc3550_buf[i] == 0xff) {
14410 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
14411 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14412 _adv_asc3550_buf
14413 [i +
14414 3] << 8) |
14415 _adv_asc3550_buf
14416 [i + 2]));
14417 word++;
14418 }
14419 i += 3;
14420 } else if (_adv_asc3550_buf[i] == 0xfe) {
14421 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14422 _adv_asc3550_buf[i +
14423 2]
14424 << 8) |
14425 _adv_asc3550_buf[i +
14426 1]));
14427 i += 2;
14428 word++;
14429 } else {
14430 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14431 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
14432 word++;
14433 }
14434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014435
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014436 /*
14437 * Set 'word' for later use to clear the rest of memory and save
14438 * the expanded mcode size.
14439 */
14440 word *= 2;
14441 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014442
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014443 /*
14444 * Clear the rest of ASC-3550 Internal RAM (8KB).
14445 */
14446 for (; word < ADV_3550_MEMSIZE; word += 2) {
14447 AdvWriteWordAutoIncLram(iop_base, 0);
14448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014449
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014450 /*
14451 * Verify the microcode checksum.
14452 */
14453 sum = 0;
14454 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014455
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014456 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
14457 sum += AdvReadWordAutoIncLram(iop_base);
14458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014459
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014460 if (sum != _adv_asc3550_chksum) {
14461 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14462 return ADV_ERROR;
14463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014464
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014465 /*
14466 * Restore the RISC memory BIOS region.
14467 */
14468 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14469 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14470 bios_mem[i]);
14471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014473 /*
14474 * Calculate and write the microcode code checksum to the microcode
14475 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14476 */
14477 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14478 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14479 code_sum = 0;
14480 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14481 for (word = begin_addr; word < end_addr; word += 2) {
14482 code_sum += AdvReadWordAutoIncLram(iop_base);
14483 }
14484 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014485
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014486 /*
14487 * Read and save microcode version and date.
14488 */
14489 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14490 asc_dvc->cfg->mcode_date);
14491 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14492 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014494 /*
14495 * Set the chip type to indicate the ASC3550.
14496 */
14497 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014498
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014499 /*
14500 * If the PCI Configuration Command Register "Parity Error Response
14501 * Control" Bit was clear (0), then set the microcode variable
14502 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14503 * to ignore DMA parity errors.
14504 */
14505 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14506 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14507 word |= CONTROL_FLAG_IGNORE_PERR;
14508 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014510
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014511 /*
14512 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
14513 * threshold of 128 bytes. This register is only accessible to the host.
14514 */
14515 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14516 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014517
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014518 /*
14519 * Microcode operating variables for WDTR, SDTR, and command tag
14520 * queuing will be set in AdvInquiryHandling() based on what a
14521 * device reports it is capable of in Inquiry byte 7.
14522 *
14523 * If SCSI Bus Resets have been disabled, then directly set
14524 * SDTR and WDTR from the EEPROM configuration. This will allow
14525 * the BIOS and warm boot to work without a SCSI bus hang on
14526 * the Inquiry caused by host and target mismatched DTR values.
14527 * Without the SCSI Bus Reset, before an Inquiry a device can't
14528 * be assumed to be in Asynchronous, Narrow mode.
14529 */
14530 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14531 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14532 asc_dvc->wdtr_able);
14533 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14534 asc_dvc->sdtr_able);
14535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014536
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014537 /*
14538 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
14539 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
14540 * bitmask. These values determine the maximum SDTR speed negotiated
14541 * with a device.
14542 *
14543 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14544 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14545 * without determining here whether the device supports SDTR.
14546 *
14547 * 4-bit speed SDTR speed name
14548 * =========== ===============
14549 * 0000b (0x0) SDTR disabled
14550 * 0001b (0x1) 5 Mhz
14551 * 0010b (0x2) 10 Mhz
14552 * 0011b (0x3) 20 Mhz (Ultra)
14553 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
14554 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
14555 * 0110b (0x6) Undefined
14556 * .
14557 * 1111b (0xF) Undefined
14558 */
14559 word = 0;
14560 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14561 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
14562 /* Set Ultra speed for TID 'tid'. */
14563 word |= (0x3 << (4 * (tid % 4)));
14564 } else {
14565 /* Set Fast speed for TID 'tid'. */
14566 word |= (0x2 << (4 * (tid % 4)));
14567 }
14568 if (tid == 3) { /* Check if done with sdtr_speed1. */
14569 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
14570 word = 0;
14571 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
14572 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
14573 word = 0;
14574 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
14575 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
14576 word = 0;
14577 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
14578 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
14579 /* End of loop. */
14580 }
14581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014582
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014583 /*
14584 * Set microcode operating variable for the disconnect per TID bitmask.
14585 */
14586 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14587 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014588
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014589 /*
14590 * Set SCSI_CFG0 Microcode Default Value.
14591 *
14592 * The microcode will set the SCSI_CFG0 register using this value
14593 * after it is started below.
14594 */
14595 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14596 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14597 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014598
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014599 /*
14600 * Determine SCSI_CFG1 Microcode Default Value.
14601 *
14602 * The microcode will set the SCSI_CFG1 register using this value
14603 * after it is started below.
14604 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014605
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014606 /* Read current SCSI_CFG1 Register value. */
14607 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014608
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014609 /*
14610 * If all three connectors are in use, return an error.
14611 */
14612 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
14613 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
14614 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
14615 return ADV_ERROR;
14616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014617
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014618 /*
14619 * If the internal narrow cable is reversed all of the SCSI_CTRL
14620 * register signals will be set. Check for and return an error if
14621 * this condition is found.
14622 */
14623 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14624 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14625 return ADV_ERROR;
14626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014627
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014628 /*
14629 * If this is a differential board and a single-ended device
14630 * is attached to one of the connectors, return an error.
14631 */
14632 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
14633 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
14634 return ADV_ERROR;
14635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014636
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014637 /*
14638 * If automatic termination control is enabled, then set the
14639 * termination value based on a table listed in a_condor.h.
14640 *
14641 * If manual termination was specified with an EEPROM setting
14642 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
14643 * is ready to be 'ored' into SCSI_CFG1.
14644 */
14645 if (asc_dvc->cfg->termination == 0) {
14646 /*
14647 * The software always controls termination by setting TERM_CTL_SEL.
14648 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
14649 */
14650 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014651
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014652 switch (scsi_cfg1 & CABLE_DETECT) {
14653 /* TERM_CTL_H: on, TERM_CTL_L: on */
14654 case 0x3:
14655 case 0x7:
14656 case 0xB:
14657 case 0xD:
14658 case 0xE:
14659 case 0xF:
14660 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
14661 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014662
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014663 /* TERM_CTL_H: on, TERM_CTL_L: off */
14664 case 0x1:
14665 case 0x5:
14666 case 0x9:
14667 case 0xA:
14668 case 0xC:
14669 asc_dvc->cfg->termination |= TERM_CTL_H;
14670 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014671
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014672 /* TERM_CTL_H: off, TERM_CTL_L: off */
14673 case 0x2:
14674 case 0x6:
14675 break;
14676 }
14677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014678
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014679 /*
14680 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
14681 */
14682 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014683
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014684 /*
14685 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
14686 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
14687 * referenced, because the hardware internally inverts
14688 * the Termination High and Low bits if TERM_POL is set.
14689 */
14690 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014692 /*
14693 * Set SCSI_CFG1 Microcode Default Value
14694 *
14695 * Set filter value and possibly modified termination control
14696 * bits in the Microcode SCSI_CFG1 Register Value.
14697 *
14698 * The microcode will set the SCSI_CFG1 register using this value
14699 * after it is started below.
14700 */
14701 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14702 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014703
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014704 /*
14705 * Set MEM_CFG Microcode Default Value
14706 *
14707 * The microcode will set the MEM_CFG register using this value
14708 * after it is started below.
14709 *
14710 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14711 * are defined.
14712 *
14713 * ASC-3550 has 8KB internal memory.
14714 */
14715 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14716 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014717
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014718 /*
14719 * Set SEL_MASK Microcode Default Value
14720 *
14721 * The microcode will set the SEL_MASK register using this value
14722 * after it is started below.
14723 */
14724 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14725 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014726
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014727 /*
14728 * Build carrier freelist.
14729 *
14730 * Driver must have already allocated memory and set 'carrier_buf'.
14731 */
14732 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014733
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014734 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14735 asc_dvc->carr_freelist = NULL;
14736 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14737 buf_size = ADV_CARRIER_BUFSIZE;
14738 } else {
14739 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014741
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014742 do {
14743 /*
14744 * Get physical address of the carrier 'carrp'.
14745 */
14746 contig_len = sizeof(ADV_CARR_T);
14747 carr_paddr =
14748 cpu_to_le32(DvcGetPhyAddr
14749 (asc_dvc, NULL, (uchar *)carrp,
14750 (ADV_SDCNT *)&contig_len,
14751 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014752
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014753 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014754
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014755 /*
14756 * If the current carrier is not physically contiguous, then
14757 * maybe there was a page crossing. Try the next carrier aligned
14758 * start address.
14759 */
14760 if (contig_len < sizeof(ADV_CARR_T)) {
14761 carrp++;
14762 continue;
14763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014764
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014765 carrp->carr_pa = carr_paddr;
14766 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014767
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014768 /*
14769 * Insert the carrier at the beginning of the freelist.
14770 */
14771 carrp->next_vpa =
14772 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14773 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014774
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014775 carrp++;
14776 }
14777 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014778
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014779 /*
14780 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14781 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014782
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014783 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14784 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14785 return ADV_ERROR;
14786 }
14787 asc_dvc->carr_freelist = (ADV_CARR_T *)
14788 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014789
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014790 /*
14791 * The first command issued will be placed in the stopper carrier.
14792 */
14793 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014794
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014795 /*
14796 * Set RISC ICQ physical address start value.
14797 */
14798 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014799
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014800 /*
14801 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14802 */
14803 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14804 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14805 return ADV_ERROR;
14806 }
14807 asc_dvc->carr_freelist = (ADV_CARR_T *)
14808 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014809
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014810 /*
14811 * The first command completed by the RISC will be placed in
14812 * the stopper.
14813 *
14814 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14815 * completed the RISC will set the ASC_RQ_STOPPER bit.
14816 */
14817 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014818
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014819 /*
14820 * Set RISC IRQ physical address start value.
14821 */
14822 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14823 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014824
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014825 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14826 (ADV_INTR_ENABLE_HOST_INTR |
14827 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014828
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014829 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14830 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014831
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014832 /* finally, finally, gentlemen, start your engine */
14833 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014834
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014835 /*
14836 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14837 * Resets should be performed. The RISC has to be running
14838 * to issue a SCSI Bus Reset.
14839 */
14840 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14841 /*
14842 * If the BIOS Signature is present in memory, restore the
14843 * BIOS Handshake Configuration Table and do not perform
14844 * a SCSI Bus Reset.
14845 */
14846 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14847 0x55AA) {
14848 /*
14849 * Restore per TID negotiated values.
14850 */
14851 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14852 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14853 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14854 tagqng_able);
14855 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14856 AdvWriteByteLram(iop_base,
14857 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14858 max_cmd[tid]);
14859 }
14860 } else {
14861 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14862 warn_code = ASC_WARN_BUSRESET_ERROR;
14863 }
14864 }
14865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014866
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014867 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014868}
14869
14870/*
14871 * Initialize the ASC-38C0800.
14872 *
14873 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14874 *
14875 * For a non-fatal error return a warning code. If there are no warnings
14876 * then 0 is returned.
14877 *
14878 * Needed after initialization for error recovery.
14879 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014880static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014881{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014882 AdvPortAddr iop_base;
14883 ushort warn_code;
14884 ADV_DCNT sum;
14885 int begin_addr;
14886 int end_addr;
14887 ushort code_sum;
14888 int word;
14889 int j;
14890 int adv_asc38C0800_expanded_size;
14891 ADV_CARR_T *carrp;
14892 ADV_DCNT contig_len;
14893 ADV_SDCNT buf_size;
14894 ADV_PADDR carr_paddr;
14895 int i;
14896 ushort scsi_cfg1;
14897 uchar byte;
14898 uchar tid;
14899 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14900 ushort wdtr_able, sdtr_able, tagqng_able;
14901 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014902
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014903 /* If there is already an error, don't continue. */
14904 if (asc_dvc->err_code != 0) {
14905 return ADV_ERROR;
14906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014907
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014908 /*
14909 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14910 */
14911 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14912 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14913 return ADV_ERROR;
14914 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014915
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014916 warn_code = 0;
14917 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014918
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014919 /*
14920 * Save the RISC memory BIOS region before writing the microcode.
14921 * The BIOS may already be loaded and using its RISC LRAM region
14922 * so its region must be saved and restored.
14923 *
14924 * Note: This code makes the assumption, which is currently true,
14925 * that a chip reset does not clear RISC LRAM.
14926 */
14927 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14928 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14929 bios_mem[i]);
14930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014931
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014932 /*
14933 * Save current per TID negotiated values.
14934 */
14935 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14936 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14937 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14938 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14939 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14940 max_cmd[tid]);
14941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014942
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014943 /*
14944 * RAM BIST (RAM Built-In Self Test)
14945 *
14946 * Address : I/O base + offset 0x38h register (byte).
14947 * Function: Bit 7-6(RW) : RAM mode
14948 * Normal Mode : 0x00
14949 * Pre-test Mode : 0x40
14950 * RAM Test Mode : 0x80
14951 * Bit 5 : unused
14952 * Bit 4(RO) : Done bit
14953 * Bit 3-0(RO) : Status
14954 * Host Error : 0x08
14955 * Int_RAM Error : 0x04
14956 * RISC Error : 0x02
14957 * SCSI Error : 0x01
14958 * No Error : 0x00
14959 *
14960 * Note: RAM BIST code should be put right here, before loading the
14961 * microcode and after saving the RISC memory BIOS region.
14962 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014963
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014964 /*
14965 * LRAM Pre-test
14966 *
14967 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14968 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14969 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14970 * to NORMAL_MODE, return an error too.
14971 */
14972 for (i = 0; i < 2; i++) {
14973 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14974 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14975 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14976 if ((byte & RAM_TEST_DONE) == 0
14977 || (byte & 0x0F) != PRE_TEST_VALUE) {
14978 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14979 return ADV_ERROR;
14980 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014981
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014982 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14983 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14984 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14985 != NORMAL_VALUE) {
14986 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14987 return ADV_ERROR;
14988 }
14989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014990
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014991 /*
14992 * LRAM Test - It takes about 1.5 ms to run through the test.
14993 *
14994 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14995 * If Done bit not set or Status not 0, save register byte, set the
14996 * err_code, and return an error.
14997 */
14998 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14999 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015000
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015001 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15002 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
15003 /* Get here if Done bit not set or Status not 0. */
15004 asc_dvc->bist_err_code = byte; /* for BIOS display message */
15005 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
15006 return ADV_ERROR;
15007 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015008
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015009 /* We need to reset back to normal mode after LRAM test passes. */
15010 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015011
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015012 /*
15013 * Load the Microcode
15014 *
15015 * Write the microcode image to RISC memory starting at address 0.
15016 *
15017 */
15018 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015019
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015020 /* Assume the following compressed format of the microcode buffer:
15021 *
15022 * 254 word (508 byte) table indexed by byte code followed
15023 * by the following byte codes:
15024 *
15025 * 1-Byte Code:
15026 * 00: Emit word 0 in table.
15027 * 01: Emit word 1 in table.
15028 * .
15029 * FD: Emit word 253 in table.
15030 *
15031 * Multi-Byte Code:
15032 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15033 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15034 */
15035 word = 0;
15036 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
15037 if (_adv_asc38C0800_buf[i] == 0xff) {
15038 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
15039 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15040 _adv_asc38C0800_buf
15041 [i +
15042 3] << 8) |
15043 _adv_asc38C0800_buf
15044 [i + 2]));
15045 word++;
15046 }
15047 i += 3;
15048 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
15049 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15050 _adv_asc38C0800_buf
15051 [i +
15052 2] << 8) |
15053 _adv_asc38C0800_buf[i
15054 +
15055 1]));
15056 i += 2;
15057 word++;
15058 } else {
15059 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15060 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
15061 word++;
15062 }
15063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015064
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015065 /*
15066 * Set 'word' for later use to clear the rest of memory and save
15067 * the expanded mcode size.
15068 */
15069 word *= 2;
15070 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015071
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015072 /*
15073 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
15074 */
15075 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
15076 AdvWriteWordAutoIncLram(iop_base, 0);
15077 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015078
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015079 /*
15080 * Verify the microcode checksum.
15081 */
15082 sum = 0;
15083 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015084
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015085 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
15086 sum += AdvReadWordAutoIncLram(iop_base);
15087 }
15088 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015089
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015090 ASC_DBG2(1,
15091 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
15092 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015094 if (sum != _adv_asc38C0800_chksum) {
15095 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15096 return ADV_ERROR;
15097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015098
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015099 /*
15100 * Restore the RISC memory BIOS region.
15101 */
15102 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15103 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15104 bios_mem[i]);
15105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015106
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015107 /*
15108 * Calculate and write the microcode code checksum to the microcode
15109 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15110 */
15111 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15112 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15113 code_sum = 0;
15114 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15115 for (word = begin_addr; word < end_addr; word += 2) {
15116 code_sum += AdvReadWordAutoIncLram(iop_base);
15117 }
15118 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015119
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015120 /*
15121 * Read microcode version and date.
15122 */
15123 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15124 asc_dvc->cfg->mcode_date);
15125 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15126 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015127
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015128 /*
15129 * Set the chip type to indicate the ASC38C0800.
15130 */
15131 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015132
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015133 /*
15134 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15135 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15136 * cable detection and then we are able to read C_DET[3:0].
15137 *
15138 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15139 * Microcode Default Value' section below.
15140 */
15141 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15142 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15143 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015144
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015145 /*
15146 * If the PCI Configuration Command Register "Parity Error Response
15147 * Control" Bit was clear (0), then set the microcode variable
15148 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15149 * to ignore DMA parity errors.
15150 */
15151 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15152 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15153 word |= CONTROL_FLAG_IGNORE_PERR;
15154 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015156
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015157 /*
15158 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
15159 * bits for the default FIFO threshold.
15160 *
15161 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
15162 *
15163 * For DMA Errata #4 set the BC_THRESH_ENB bit.
15164 */
15165 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15166 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
15167 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015168
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015169 /*
15170 * Microcode operating variables for WDTR, SDTR, and command tag
15171 * queuing will be set in AdvInquiryHandling() based on what a
15172 * device reports it is capable of in Inquiry byte 7.
15173 *
15174 * If SCSI Bus Resets have been disabled, then directly set
15175 * SDTR and WDTR from the EEPROM configuration. This will allow
15176 * the BIOS and warm boot to work without a SCSI bus hang on
15177 * the Inquiry caused by host and target mismatched DTR values.
15178 * Without the SCSI Bus Reset, before an Inquiry a device can't
15179 * be assumed to be in Asynchronous, Narrow mode.
15180 */
15181 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15182 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15183 asc_dvc->wdtr_able);
15184 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15185 asc_dvc->sdtr_able);
15186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015187
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015188 /*
15189 * Set microcode operating variables for DISC and SDTR_SPEED1,
15190 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15191 * configuration values.
15192 *
15193 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15194 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15195 * without determining here whether the device supports SDTR.
15196 */
15197 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15198 asc_dvc->cfg->disc_enable);
15199 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15200 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15201 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15202 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015203
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015204 /*
15205 * Set SCSI_CFG0 Microcode Default Value.
15206 *
15207 * The microcode will set the SCSI_CFG0 register using this value
15208 * after it is started below.
15209 */
15210 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15211 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15212 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015213
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015214 /*
15215 * Determine SCSI_CFG1 Microcode Default Value.
15216 *
15217 * The microcode will set the SCSI_CFG1 register using this value
15218 * after it is started below.
15219 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015220
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015221 /* Read current SCSI_CFG1 Register value. */
15222 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015223
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015224 /*
15225 * If the internal narrow cable is reversed all of the SCSI_CTRL
15226 * register signals will be set. Check for and return an error if
15227 * this condition is found.
15228 */
15229 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15230 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15231 return ADV_ERROR;
15232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015233
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015234 /*
15235 * All kind of combinations of devices attached to one of four connectors
15236 * are acceptable except HVD device attached. For example, LVD device can
15237 * be attached to SE connector while SE device attached to LVD connector.
15238 * If LVD device attached to SE connector, it only runs up to Ultra speed.
15239 *
15240 * If an HVD device is attached to one of LVD connectors, return an error.
15241 * However, there is no way to detect HVD device attached to SE connectors.
15242 */
15243 if (scsi_cfg1 & HVD) {
15244 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15245 return ADV_ERROR;
15246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015247
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015248 /*
15249 * If either SE or LVD automatic termination control is enabled, then
15250 * set the termination value based on a table listed in a_condor.h.
15251 *
15252 * If manual termination was specified with an EEPROM setting then
15253 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
15254 * be 'ored' into SCSI_CFG1.
15255 */
15256 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15257 /* SE automatic termination control is enabled. */
15258 switch (scsi_cfg1 & C_DET_SE) {
15259 /* TERM_SE_HI: on, TERM_SE_LO: on */
15260 case 0x1:
15261 case 0x2:
15262 case 0x3:
15263 asc_dvc->cfg->termination |= TERM_SE;
15264 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015265
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015266 /* TERM_SE_HI: on, TERM_SE_LO: off */
15267 case 0x0:
15268 asc_dvc->cfg->termination |= TERM_SE_HI;
15269 break;
15270 }
15271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015272
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015273 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
15274 /* LVD automatic termination control is enabled. */
15275 switch (scsi_cfg1 & C_DET_LVD) {
15276 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
15277 case 0x4:
15278 case 0x8:
15279 case 0xC:
15280 asc_dvc->cfg->termination |= TERM_LVD;
15281 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015283 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
15284 case 0x0:
15285 break;
15286 }
15287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015288
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015289 /*
15290 * Clear any set TERM_SE and TERM_LVD bits.
15291 */
15292 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015293
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015294 /*
15295 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
15296 */
15297 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015298
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015299 /*
15300 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
15301 * and set possibly modified termination control bits in the Microcode
15302 * SCSI_CFG1 Register Value.
15303 */
15304 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015306 /*
15307 * Set SCSI_CFG1 Microcode Default Value
15308 *
15309 * Set possibly modified termination control and reset DIS_TERM_DRV
15310 * bits in the Microcode SCSI_CFG1 Register Value.
15311 *
15312 * The microcode will set the SCSI_CFG1 register using this value
15313 * after it is started below.
15314 */
15315 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015316
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015317 /*
15318 * Set MEM_CFG Microcode Default Value
15319 *
15320 * The microcode will set the MEM_CFG register using this value
15321 * after it is started below.
15322 *
15323 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15324 * are defined.
15325 *
15326 * ASC-38C0800 has 16KB internal memory.
15327 */
15328 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15329 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015330
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015331 /*
15332 * Set SEL_MASK Microcode Default Value
15333 *
15334 * The microcode will set the SEL_MASK register using this value
15335 * after it is started below.
15336 */
15337 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15338 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015339
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015340 /*
15341 * Build the carrier freelist.
15342 *
15343 * Driver must have already allocated memory and set 'carrier_buf'.
15344 */
15345 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015346
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015347 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15348 asc_dvc->carr_freelist = NULL;
15349 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15350 buf_size = ADV_CARRIER_BUFSIZE;
15351 } else {
15352 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015354
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015355 do {
15356 /*
15357 * Get physical address for the carrier 'carrp'.
15358 */
15359 contig_len = sizeof(ADV_CARR_T);
15360 carr_paddr =
15361 cpu_to_le32(DvcGetPhyAddr
15362 (asc_dvc, NULL, (uchar *)carrp,
15363 (ADV_SDCNT *)&contig_len,
15364 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015365
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015366 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015367
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015368 /*
15369 * If the current carrier is not physically contiguous, then
15370 * maybe there was a page crossing. Try the next carrier aligned
15371 * start address.
15372 */
15373 if (contig_len < sizeof(ADV_CARR_T)) {
15374 carrp++;
15375 continue;
15376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015377
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015378 carrp->carr_pa = carr_paddr;
15379 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015380
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015381 /*
15382 * Insert the carrier at the beginning of the freelist.
15383 */
15384 carrp->next_vpa =
15385 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15386 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015387
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015388 carrp++;
15389 }
15390 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015391
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015392 /*
15393 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15394 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015395
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015396 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15397 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15398 return ADV_ERROR;
15399 }
15400 asc_dvc->carr_freelist = (ADV_CARR_T *)
15401 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015402
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015403 /*
15404 * The first command issued will be placed in the stopper carrier.
15405 */
15406 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015407
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015408 /*
15409 * Set RISC ICQ physical address start value.
15410 * carr_pa is LE, must be native before write
15411 */
15412 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015413
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015414 /*
15415 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15416 */
15417 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15418 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15419 return ADV_ERROR;
15420 }
15421 asc_dvc->carr_freelist = (ADV_CARR_T *)
15422 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015423
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015424 /*
15425 * The first command completed by the RISC will be placed in
15426 * the stopper.
15427 *
15428 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15429 * completed the RISC will set the ASC_RQ_STOPPER bit.
15430 */
15431 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015432
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015433 /*
15434 * Set RISC IRQ physical address start value.
15435 *
15436 * carr_pa is LE, must be native before write *
15437 */
15438 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15439 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015441 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15442 (ADV_INTR_ENABLE_HOST_INTR |
15443 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015444
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015445 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15446 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015447
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015448 /* finally, finally, gentlemen, start your engine */
15449 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015450
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015451 /*
15452 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15453 * Resets should be performed. The RISC has to be running
15454 * to issue a SCSI Bus Reset.
15455 */
15456 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15457 /*
15458 * If the BIOS Signature is present in memory, restore the
15459 * BIOS Handshake Configuration Table and do not perform
15460 * a SCSI Bus Reset.
15461 */
15462 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15463 0x55AA) {
15464 /*
15465 * Restore per TID negotiated values.
15466 */
15467 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15468 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15469 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15470 tagqng_able);
15471 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15472 AdvWriteByteLram(iop_base,
15473 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15474 max_cmd[tid]);
15475 }
15476 } else {
15477 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15478 warn_code = ASC_WARN_BUSRESET_ERROR;
15479 }
15480 }
15481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015482
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015483 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015484}
15485
15486/*
15487 * Initialize the ASC-38C1600.
15488 *
15489 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15490 *
15491 * For a non-fatal error return a warning code. If there are no warnings
15492 * then 0 is returned.
15493 *
15494 * Needed after initialization for error recovery.
15495 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015496static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015497{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015498 AdvPortAddr iop_base;
15499 ushort warn_code;
15500 ADV_DCNT sum;
15501 int begin_addr;
15502 int end_addr;
15503 ushort code_sum;
15504 long word;
15505 int j;
15506 int adv_asc38C1600_expanded_size;
15507 ADV_CARR_T *carrp;
15508 ADV_DCNT contig_len;
15509 ADV_SDCNT buf_size;
15510 ADV_PADDR carr_paddr;
15511 int i;
15512 ushort scsi_cfg1;
15513 uchar byte;
15514 uchar tid;
15515 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
15516 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
15517 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070015518
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015519 /* If there is already an error, don't continue. */
15520 if (asc_dvc->err_code != 0) {
15521 return ADV_ERROR;
15522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015523
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015524 /*
15525 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
15526 */
15527 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
15528 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
15529 return ADV_ERROR;
15530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015531
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015532 warn_code = 0;
15533 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015535 /*
15536 * Save the RISC memory BIOS region before writing the microcode.
15537 * The BIOS may already be loaded and using its RISC LRAM region
15538 * so its region must be saved and restored.
15539 *
15540 * Note: This code makes the assumption, which is currently true,
15541 * that a chip reset does not clear RISC LRAM.
15542 */
15543 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15544 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15545 bios_mem[i]);
15546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015547
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015548 /*
15549 * Save current per TID negotiated values.
15550 */
15551 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15552 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15553 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15554 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
15555 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15556 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
15557 max_cmd[tid]);
15558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015559
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015560 /*
15561 * RAM BIST (Built-In Self Test)
15562 *
15563 * Address : I/O base + offset 0x38h register (byte).
15564 * Function: Bit 7-6(RW) : RAM mode
15565 * Normal Mode : 0x00
15566 * Pre-test Mode : 0x40
15567 * RAM Test Mode : 0x80
15568 * Bit 5 : unused
15569 * Bit 4(RO) : Done bit
15570 * Bit 3-0(RO) : Status
15571 * Host Error : 0x08
15572 * Int_RAM Error : 0x04
15573 * RISC Error : 0x02
15574 * SCSI Error : 0x01
15575 * No Error : 0x00
15576 *
15577 * Note: RAM BIST code should be put right here, before loading the
15578 * microcode and after saving the RISC memory BIOS region.
15579 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015580
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015581 /*
15582 * LRAM Pre-test
15583 *
15584 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
15585 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
15586 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
15587 * to NORMAL_MODE, return an error too.
15588 */
15589 for (i = 0; i < 2; i++) {
15590 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
15591 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15592 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15593 if ((byte & RAM_TEST_DONE) == 0
15594 || (byte & 0x0F) != PRE_TEST_VALUE) {
15595 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15596 return ADV_ERROR;
15597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015598
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015599 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
15600 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15601 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
15602 != NORMAL_VALUE) {
15603 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15604 return ADV_ERROR;
15605 }
15606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015607
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015608 /*
15609 * LRAM Test - It takes about 1.5 ms to run through the test.
15610 *
15611 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
15612 * If Done bit not set or Status not 0, save register byte, set the
15613 * err_code, and return an error.
15614 */
15615 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
15616 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015617
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015618 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15619 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
15620 /* Get here if Done bit not set or Status not 0. */
15621 asc_dvc->bist_err_code = byte; /* for BIOS display message */
15622 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
15623 return ADV_ERROR;
15624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015625
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015626 /* We need to reset back to normal mode after LRAM test passes. */
15627 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015629 /*
15630 * Load the Microcode
15631 *
15632 * Write the microcode image to RISC memory starting at address 0.
15633 *
15634 */
15635 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015636
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015637 /*
15638 * Assume the following compressed format of the microcode buffer:
15639 *
15640 * 254 word (508 byte) table indexed by byte code followed
15641 * by the following byte codes:
15642 *
15643 * 1-Byte Code:
15644 * 00: Emit word 0 in table.
15645 * 01: Emit word 1 in table.
15646 * .
15647 * FD: Emit word 253 in table.
15648 *
15649 * Multi-Byte Code:
15650 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15651 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15652 */
15653 word = 0;
15654 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
15655 if (_adv_asc38C1600_buf[i] == 0xff) {
15656 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
15657 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15658 _adv_asc38C1600_buf
15659 [i +
15660 3] << 8) |
15661 _adv_asc38C1600_buf
15662 [i + 2]));
15663 word++;
15664 }
15665 i += 3;
15666 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
15667 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15668 _adv_asc38C1600_buf
15669 [i +
15670 2] << 8) |
15671 _adv_asc38C1600_buf[i
15672 +
15673 1]));
15674 i += 2;
15675 word++;
15676 } else {
15677 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15678 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
15679 word++;
15680 }
15681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015682
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015683 /*
15684 * Set 'word' for later use to clear the rest of memory and save
15685 * the expanded mcode size.
15686 */
15687 word *= 2;
15688 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015689
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015690 /*
15691 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15692 */
15693 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15694 AdvWriteWordAutoIncLram(iop_base, 0);
15695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015696
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015697 /*
15698 * Verify the microcode checksum.
15699 */
15700 sum = 0;
15701 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015702
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015703 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15704 sum += AdvReadWordAutoIncLram(iop_base);
15705 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015706
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015707 if (sum != _adv_asc38C1600_chksum) {
15708 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15709 return ADV_ERROR;
15710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015711
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015712 /*
15713 * Restore the RISC memory BIOS region.
15714 */
15715 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15716 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15717 bios_mem[i]);
15718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015720 /*
15721 * Calculate and write the microcode code checksum to the microcode
15722 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15723 */
15724 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15725 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15726 code_sum = 0;
15727 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15728 for (word = begin_addr; word < end_addr; word += 2) {
15729 code_sum += AdvReadWordAutoIncLram(iop_base);
15730 }
15731 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015732
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015733 /*
15734 * Read microcode version and date.
15735 */
15736 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15737 asc_dvc->cfg->mcode_date);
15738 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15739 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015740
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015741 /*
15742 * Set the chip type to indicate the ASC38C1600.
15743 */
15744 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015746 /*
15747 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15748 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15749 * cable detection and then we are able to read C_DET[3:0].
15750 *
15751 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15752 * Microcode Default Value' section below.
15753 */
15754 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15755 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15756 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015757
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015758 /*
15759 * If the PCI Configuration Command Register "Parity Error Response
15760 * Control" Bit was clear (0), then set the microcode variable
15761 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15762 * to ignore DMA parity errors.
15763 */
15764 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15765 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15766 word |= CONTROL_FLAG_IGNORE_PERR;
15767 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015770 /*
15771 * If the BIOS control flag AIPP (Asynchronous Information
15772 * Phase Protection) disable bit is not set, then set the firmware
15773 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15774 * AIPP checking and encoding.
15775 */
15776 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15777 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15778 word |= CONTROL_FLAG_ENABLE_AIPP;
15779 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015781
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015782 /*
15783 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15784 * and START_CTL_TH [3:2].
15785 */
15786 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15787 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015788
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015789 /*
15790 * Microcode operating variables for WDTR, SDTR, and command tag
15791 * queuing will be set in AdvInquiryHandling() based on what a
15792 * device reports it is capable of in Inquiry byte 7.
15793 *
15794 * If SCSI Bus Resets have been disabled, then directly set
15795 * SDTR and WDTR from the EEPROM configuration. This will allow
15796 * the BIOS and warm boot to work without a SCSI bus hang on
15797 * the Inquiry caused by host and target mismatched DTR values.
15798 * Without the SCSI Bus Reset, before an Inquiry a device can't
15799 * be assumed to be in Asynchronous, Narrow mode.
15800 */
15801 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15802 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15803 asc_dvc->wdtr_able);
15804 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15805 asc_dvc->sdtr_able);
15806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015807
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015808 /*
15809 * Set microcode operating variables for DISC and SDTR_SPEED1,
15810 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15811 * configuration values.
15812 *
15813 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15814 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15815 * without determining here whether the device supports SDTR.
15816 */
15817 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15818 asc_dvc->cfg->disc_enable);
15819 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15820 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15821 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15822 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015823
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015824 /*
15825 * Set SCSI_CFG0 Microcode Default Value.
15826 *
15827 * The microcode will set the SCSI_CFG0 register using this value
15828 * after it is started below.
15829 */
15830 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15831 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15832 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015833
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015834 /*
15835 * Calculate SCSI_CFG1 Microcode Default Value.
15836 *
15837 * The microcode will set the SCSI_CFG1 register using this value
15838 * after it is started below.
15839 *
15840 * Each ASC-38C1600 function has only two cable detect bits.
15841 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15842 */
15843 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015844
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015845 /*
15846 * If the cable is reversed all of the SCSI_CTRL register signals
15847 * will be set. Check for and return an error if this condition is
15848 * found.
15849 */
15850 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15851 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15852 return ADV_ERROR;
15853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015854
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015855 /*
15856 * Each ASC-38C1600 function has two connectors. Only an HVD device
15857 * can not be connected to either connector. An LVD device or SE device
15858 * may be connected to either connecor. If an SE device is connected,
15859 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15860 *
15861 * If an HVD device is attached, return an error.
15862 */
15863 if (scsi_cfg1 & HVD) {
15864 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15865 return ADV_ERROR;
15866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015867
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015868 /*
15869 * Each function in the ASC-38C1600 uses only the SE cable detect and
15870 * termination because there are two connectors for each function. Each
15871 * function may use either LVD or SE mode. Corresponding the SE automatic
15872 * termination control EEPROM bits are used for each function. Each
15873 * function has its own EEPROM. If SE automatic control is enabled for
15874 * the function, then set the termination value based on a table listed
15875 * in a_condor.h.
15876 *
15877 * If manual termination is specified in the EEPROM for the function,
15878 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15879 * ready to be 'ored' into SCSI_CFG1.
15880 */
15881 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15882 /* SE automatic termination control is enabled. */
15883 switch (scsi_cfg1 & C_DET_SE) {
15884 /* TERM_SE_HI: on, TERM_SE_LO: on */
15885 case 0x1:
15886 case 0x2:
15887 case 0x3:
15888 asc_dvc->cfg->termination |= TERM_SE;
15889 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015890
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015891 case 0x0:
15892 if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
15893 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15894 } else {
15895 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15896 asc_dvc->cfg->termination |= TERM_SE_HI;
15897 }
15898 break;
15899 }
15900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015901
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015902 /*
15903 * Clear any set TERM_SE bits.
15904 */
15905 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015906
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015907 /*
15908 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15909 */
15910 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015911
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015912 /*
15913 * Clear Big Endian and Terminator Polarity bits and set possibly
15914 * modified termination control bits in the Microcode SCSI_CFG1
15915 * Register Value.
15916 *
15917 * Big Endian bit is not used even on big endian machines.
15918 */
15919 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015920
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015921 /*
15922 * Set SCSI_CFG1 Microcode Default Value
15923 *
15924 * Set possibly modified termination control bits in the Microcode
15925 * SCSI_CFG1 Register Value.
15926 *
15927 * The microcode will set the SCSI_CFG1 register using this value
15928 * after it is started below.
15929 */
15930 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015931
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015932 /*
15933 * Set MEM_CFG Microcode Default Value
15934 *
15935 * The microcode will set the MEM_CFG register using this value
15936 * after it is started below.
15937 *
15938 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15939 * are defined.
15940 *
15941 * ASC-38C1600 has 32KB internal memory.
15942 *
15943 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15944 * out a special 16K Adv Library and Microcode version. After the issue
15945 * resolved, we should turn back to the 32K support. Both a_condor.h and
15946 * mcode.sas files also need to be updated.
15947 *
15948 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15949 * BIOS_EN | RAM_SZ_32KB);
15950 */
15951 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15952 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015953
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015954 /*
15955 * Set SEL_MASK Microcode Default Value
15956 *
15957 * The microcode will set the SEL_MASK register using this value
15958 * after it is started below.
15959 */
15960 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15961 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015962
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015963 /*
15964 * Build the carrier freelist.
15965 *
15966 * Driver must have already allocated memory and set 'carrier_buf'.
15967 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015968
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015969 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015970
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015971 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15972 asc_dvc->carr_freelist = NULL;
15973 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15974 buf_size = ADV_CARRIER_BUFSIZE;
15975 } else {
15976 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015978
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015979 do {
15980 /*
15981 * Get physical address for the carrier 'carrp'.
15982 */
15983 contig_len = sizeof(ADV_CARR_T);
15984 carr_paddr =
15985 cpu_to_le32(DvcGetPhyAddr
15986 (asc_dvc, NULL, (uchar *)carrp,
15987 (ADV_SDCNT *)&contig_len,
15988 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015989
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015990 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015991
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015992 /*
15993 * If the current carrier is not physically contiguous, then
15994 * maybe there was a page crossing. Try the next carrier aligned
15995 * start address.
15996 */
15997 if (contig_len < sizeof(ADV_CARR_T)) {
15998 carrp++;
15999 continue;
16000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016001
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016002 carrp->carr_pa = carr_paddr;
16003 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016004
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016005 /*
16006 * Insert the carrier at the beginning of the freelist.
16007 */
16008 carrp->next_vpa =
16009 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
16010 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016011
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016012 carrp++;
16013 }
16014 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016015
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016016 /*
16017 * Set-up the Host->RISC Initiator Command Queue (ICQ).
16018 */
16019 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
16020 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
16021 return ADV_ERROR;
16022 }
16023 asc_dvc->carr_freelist = (ADV_CARR_T *)
16024 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016025
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016026 /*
16027 * The first command issued will be placed in the stopper carrier.
16028 */
16029 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016031 /*
16032 * Set RISC ICQ physical address start value. Initialize the
16033 * COMMA register to the same value otherwise the RISC will
16034 * prematurely detect a command is available.
16035 */
16036 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
16037 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
16038 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016039
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016040 /*
16041 * Set-up the RISC->Host Initiator Response Queue (IRQ).
16042 */
16043 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
16044 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
16045 return ADV_ERROR;
16046 }
16047 asc_dvc->carr_freelist = (ADV_CARR_T *)
16048 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016049
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016050 /*
16051 * The first command completed by the RISC will be placed in
16052 * the stopper.
16053 *
16054 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
16055 * completed the RISC will set the ASC_RQ_STOPPER bit.
16056 */
16057 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016058
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016059 /*
16060 * Set RISC IRQ physical address start value.
16061 */
16062 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
16063 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016064
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016065 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
16066 (ADV_INTR_ENABLE_HOST_INTR |
16067 ADV_INTR_ENABLE_GLOBAL_INTR));
16068 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
16069 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016070
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016071 /* finally, finally, gentlemen, start your engine */
16072 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016073
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016074 /*
16075 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
16076 * Resets should be performed. The RISC has to be running
16077 * to issue a SCSI Bus Reset.
16078 */
16079 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
16080 /*
16081 * If the BIOS Signature is present in memory, restore the
16082 * per TID microcode operating variables.
16083 */
16084 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
16085 0x55AA) {
16086 /*
16087 * Restore per TID negotiated values.
16088 */
16089 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16090 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16091 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16092 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
16093 tagqng_able);
16094 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
16095 AdvWriteByteLram(iop_base,
16096 ASC_MC_NUMBER_OF_MAX_CMD + tid,
16097 max_cmd[tid]);
16098 }
16099 } else {
16100 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
16101 warn_code = ASC_WARN_BUSRESET_ERROR;
16102 }
16103 }
16104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016105
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016106 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016107}
16108
16109/*
16110 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
16111 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
16112 * all of this is done.
16113 *
16114 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
16115 *
16116 * For a non-fatal error return a warning code. If there are no warnings
16117 * then 0 is returned.
16118 *
16119 * Note: Chip is stopped on entry.
16120 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016121static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016122{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016123 AdvPortAddr iop_base;
16124 ushort warn_code;
16125 ADVEEP_3550_CONFIG eep_config;
16126 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016127
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016128 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016129
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016130 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016131
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016132 /*
16133 * Read the board's EEPROM configuration.
16134 *
16135 * Set default values if a bad checksum is found.
16136 */
16137 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
16138 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016139
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016140 /*
16141 * Set EEPROM default values.
16142 */
16143 for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
16144 *((uchar *)&eep_config + i) =
16145 *((uchar *)&Default_3550_EEPROM_Config + i);
16146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016147
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016148 /*
16149 * Assume the 6 byte board serial number that was read
16150 * from EEPROM is correct even if the EEPROM checksum
16151 * failed.
16152 */
16153 eep_config.serial_number_word3 =
16154 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016155
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016156 eep_config.serial_number_word2 =
16157 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016158
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016159 eep_config.serial_number_word1 =
16160 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016161
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016162 AdvSet3550EEPConfig(iop_base, &eep_config);
16163 }
16164 /*
16165 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
16166 * EEPROM configuration that was read.
16167 *
16168 * This is the mapping of EEPROM fields to Adv Library fields.
16169 */
16170 asc_dvc->wdtr_able = eep_config.wdtr_able;
16171 asc_dvc->sdtr_able = eep_config.sdtr_able;
16172 asc_dvc->ultra_able = eep_config.ultra_able;
16173 asc_dvc->tagqng_able = eep_config.tagqng_able;
16174 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16175 asc_dvc->max_host_qng = eep_config.max_host_qng;
16176 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16177 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
16178 asc_dvc->start_motor = eep_config.start_motor;
16179 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16180 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16181 asc_dvc->no_scam = eep_config.scam_tolerant;
16182 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
16183 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
16184 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016185
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016186 /*
16187 * Set the host maximum queuing (max. 253, min. 16) and the per device
16188 * maximum queuing (max. 63, min. 4).
16189 */
16190 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16191 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16192 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16193 /* If the value is zero, assume it is uninitialized. */
16194 if (eep_config.max_host_qng == 0) {
16195 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16196 } else {
16197 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16198 }
16199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016200
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016201 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16202 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16203 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16204 /* If the value is zero, assume it is uninitialized. */
16205 if (eep_config.max_dvc_qng == 0) {
16206 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16207 } else {
16208 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16209 }
16210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016212 /*
16213 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16214 * set 'max_dvc_qng' to 'max_host_qng'.
16215 */
16216 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16217 eep_config.max_dvc_qng = eep_config.max_host_qng;
16218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016219
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016220 /*
16221 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
16222 * values based on possibly adjusted EEPROM values.
16223 */
16224 asc_dvc->max_host_qng = eep_config.max_host_qng;
16225 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016226
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016227 /*
16228 * If the EEPROM 'termination' field is set to automatic (0), then set
16229 * the ADV_DVC_CFG 'termination' field to automatic also.
16230 *
16231 * If the termination is specified with a non-zero 'termination'
16232 * value check that a legal value is set and set the ADV_DVC_CFG
16233 * 'termination' field appropriately.
16234 */
16235 if (eep_config.termination == 0) {
16236 asc_dvc->cfg->termination = 0; /* auto termination */
16237 } else {
16238 /* Enable manual control with low off / high off. */
16239 if (eep_config.termination == 1) {
16240 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016241
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016242 /* Enable manual control with low off / high on. */
16243 } else if (eep_config.termination == 2) {
16244 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016245
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016246 /* Enable manual control with low on / high on. */
16247 } else if (eep_config.termination == 3) {
16248 asc_dvc->cfg->termination =
16249 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
16250 } else {
16251 /*
16252 * The EEPROM 'termination' field contains a bad value. Use
16253 * automatic termination instead.
16254 */
16255 asc_dvc->cfg->termination = 0;
16256 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16257 }
16258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016259
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016260 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016261}
16262
16263/*
16264 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
16265 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
16266 * all of this is done.
16267 *
16268 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
16269 *
16270 * For a non-fatal error return a warning code. If there are no warnings
16271 * then 0 is returned.
16272 *
16273 * Note: Chip is stopped on entry.
16274 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016275static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016276{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016277 AdvPortAddr iop_base;
16278 ushort warn_code;
16279 ADVEEP_38C0800_CONFIG eep_config;
16280 int i;
16281 uchar tid, termination;
16282 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016283
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016284 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016285
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016286 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016287
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016288 /*
16289 * Read the board's EEPROM configuration.
16290 *
16291 * Set default values if a bad checksum is found.
16292 */
16293 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
16294 eep_config.check_sum) {
16295 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016296
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016297 /*
16298 * Set EEPROM default values.
16299 */
16300 for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
16301 *((uchar *)&eep_config + i) =
16302 *((uchar *)&Default_38C0800_EEPROM_Config + i);
16303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016304
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016305 /*
16306 * Assume the 6 byte board serial number that was read
16307 * from EEPROM is correct even if the EEPROM checksum
16308 * failed.
16309 */
16310 eep_config.serial_number_word3 =
16311 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016312
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016313 eep_config.serial_number_word2 =
16314 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016315
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016316 eep_config.serial_number_word1 =
16317 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016318
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016319 AdvSet38C0800EEPConfig(iop_base, &eep_config);
16320 }
16321 /*
16322 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
16323 * EEPROM configuration that was read.
16324 *
16325 * This is the mapping of EEPROM fields to Adv Library fields.
16326 */
16327 asc_dvc->wdtr_able = eep_config.wdtr_able;
16328 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
16329 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
16330 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
16331 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
16332 asc_dvc->tagqng_able = eep_config.tagqng_able;
16333 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16334 asc_dvc->max_host_qng = eep_config.max_host_qng;
16335 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16336 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
16337 asc_dvc->start_motor = eep_config.start_motor;
16338 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16339 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16340 asc_dvc->no_scam = eep_config.scam_tolerant;
16341 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
16342 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
16343 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016344
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016345 /*
16346 * For every Target ID if any of its 'sdtr_speed[1234]' bits
16347 * are set, then set an 'sdtr_able' bit for it.
16348 */
16349 asc_dvc->sdtr_able = 0;
16350 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16351 if (tid == 0) {
16352 sdtr_speed = asc_dvc->sdtr_speed1;
16353 } else if (tid == 4) {
16354 sdtr_speed = asc_dvc->sdtr_speed2;
16355 } else if (tid == 8) {
16356 sdtr_speed = asc_dvc->sdtr_speed3;
16357 } else if (tid == 12) {
16358 sdtr_speed = asc_dvc->sdtr_speed4;
16359 }
16360 if (sdtr_speed & ADV_MAX_TID) {
16361 asc_dvc->sdtr_able |= (1 << tid);
16362 }
16363 sdtr_speed >>= 4;
16364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016365
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016366 /*
16367 * Set the host maximum queuing (max. 253, min. 16) and the per device
16368 * maximum queuing (max. 63, min. 4).
16369 */
16370 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16371 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16372 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16373 /* If the value is zero, assume it is uninitialized. */
16374 if (eep_config.max_host_qng == 0) {
16375 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16376 } else {
16377 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16378 }
16379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016380
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016381 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16382 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16383 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16384 /* If the value is zero, assume it is uninitialized. */
16385 if (eep_config.max_dvc_qng == 0) {
16386 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16387 } else {
16388 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16389 }
16390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016391
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016392 /*
16393 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16394 * set 'max_dvc_qng' to 'max_host_qng'.
16395 */
16396 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16397 eep_config.max_dvc_qng = eep_config.max_host_qng;
16398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016399
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016400 /*
16401 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
16402 * values based on possibly adjusted EEPROM values.
16403 */
16404 asc_dvc->max_host_qng = eep_config.max_host_qng;
16405 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016406
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016407 /*
16408 * If the EEPROM 'termination' field is set to automatic (0), then set
16409 * the ADV_DVC_CFG 'termination' field to automatic also.
16410 *
16411 * If the termination is specified with a non-zero 'termination'
16412 * value check that a legal value is set and set the ADV_DVC_CFG
16413 * 'termination' field appropriately.
16414 */
16415 if (eep_config.termination_se == 0) {
16416 termination = 0; /* auto termination for SE */
16417 } else {
16418 /* Enable manual control with low off / high off. */
16419 if (eep_config.termination_se == 1) {
16420 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016421
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016422 /* Enable manual control with low off / high on. */
16423 } else if (eep_config.termination_se == 2) {
16424 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016425
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016426 /* Enable manual control with low on / high on. */
16427 } else if (eep_config.termination_se == 3) {
16428 termination = TERM_SE;
16429 } else {
16430 /*
16431 * The EEPROM 'termination_se' field contains a bad value.
16432 * Use automatic termination instead.
16433 */
16434 termination = 0;
16435 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16436 }
16437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016438
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016439 if (eep_config.termination_lvd == 0) {
16440 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16441 } else {
16442 /* Enable manual control with low off / high off. */
16443 if (eep_config.termination_lvd == 1) {
16444 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016445
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016446 /* Enable manual control with low off / high on. */
16447 } else if (eep_config.termination_lvd == 2) {
16448 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016449
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016450 /* Enable manual control with low on / high on. */
16451 } else if (eep_config.termination_lvd == 3) {
16452 asc_dvc->cfg->termination = termination | TERM_LVD;
16453 } else {
16454 /*
16455 * The EEPROM 'termination_lvd' field contains a bad value.
16456 * Use automatic termination instead.
16457 */
16458 asc_dvc->cfg->termination = termination;
16459 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16460 }
16461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016462
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016463 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016464}
16465
16466/*
16467 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
16468 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
16469 * all of this is done.
16470 *
16471 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
16472 *
16473 * For a non-fatal error return a warning code. If there are no warnings
16474 * then 0 is returned.
16475 *
16476 * Note: Chip is stopped on entry.
16477 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016478static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016479{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016480 AdvPortAddr iop_base;
16481 ushort warn_code;
16482 ADVEEP_38C1600_CONFIG eep_config;
16483 int i;
16484 uchar tid, termination;
16485 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016486
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016487 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016488
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016489 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016490
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016491 /*
16492 * Read the board's EEPROM configuration.
16493 *
16494 * Set default values if a bad checksum is found.
16495 */
16496 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
16497 eep_config.check_sum) {
16498 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016499
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016500 /*
16501 * Set EEPROM default values.
16502 */
16503 for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
16504 if (i == 1
16505 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
16506 0) {
16507 /*
16508 * Set Function 1 EEPROM Word 0 MSB
16509 *
16510 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
16511 * EEPROM bits.
16512 *
16513 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
16514 * old Mac system booting problem. The Expansion ROM must
16515 * be disabled in Function 1 for these systems.
16516 *
16517 */
16518 *((uchar *)&eep_config + i) =
16519 ((*
16520 ((uchar *)&Default_38C1600_EEPROM_Config
16521 +
16522 i)) &
16523 (~
16524 (((ADV_EEPROM_BIOS_ENABLE |
16525 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016526
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016527 /*
16528 * Set the INTAB (bit 11) if the GPIO 0 input indicates
16529 * the Function 1 interrupt line is wired to INTA.
16530 *
16531 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
16532 * 1 - Function 1 interrupt line wired to INT A.
16533 * 0 - Function 1 interrupt line wired to INT B.
16534 *
16535 * Note: Adapter boards always have Function 0 wired to INTA.
16536 * Put all 5 GPIO bits in input mode and then read
16537 * their input values.
16538 */
16539 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
16540 0);
16541 if (AdvReadByteRegister
16542 (iop_base, IOPB_GPIO_DATA) & 0x01) {
16543 /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
16544 *((uchar *)&eep_config + i) |=
16545 ((ADV_EEPROM_INTAB >> 8) & 0xFF);
16546 }
16547 } else {
16548 *((uchar *)&eep_config + i) =
16549 *((uchar *)&Default_38C1600_EEPROM_Config
16550 + i);
16551 }
16552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016553
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016554 /*
16555 * Assume the 6 byte board serial number that was read
16556 * from EEPROM is correct even if the EEPROM checksum
16557 * failed.
16558 */
16559 eep_config.serial_number_word3 =
16560 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016561
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016562 eep_config.serial_number_word2 =
16563 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016564
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016565 eep_config.serial_number_word1 =
16566 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016567
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016568 AdvSet38C1600EEPConfig(iop_base, &eep_config);
16569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016570
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016571 /*
16572 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
16573 * EEPROM configuration that was read.
16574 *
16575 * This is the mapping of EEPROM fields to Adv Library fields.
16576 */
16577 asc_dvc->wdtr_able = eep_config.wdtr_able;
16578 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
16579 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
16580 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
16581 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
16582 asc_dvc->ppr_able = 0;
16583 asc_dvc->tagqng_able = eep_config.tagqng_able;
16584 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16585 asc_dvc->max_host_qng = eep_config.max_host_qng;
16586 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16587 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
16588 asc_dvc->start_motor = eep_config.start_motor;
16589 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16590 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16591 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016592
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016593 /*
16594 * For every Target ID if any of its 'sdtr_speed[1234]' bits
16595 * are set, then set an 'sdtr_able' bit for it.
16596 */
16597 asc_dvc->sdtr_able = 0;
16598 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
16599 if (tid == 0) {
16600 sdtr_speed = asc_dvc->sdtr_speed1;
16601 } else if (tid == 4) {
16602 sdtr_speed = asc_dvc->sdtr_speed2;
16603 } else if (tid == 8) {
16604 sdtr_speed = asc_dvc->sdtr_speed3;
16605 } else if (tid == 12) {
16606 sdtr_speed = asc_dvc->sdtr_speed4;
16607 }
16608 if (sdtr_speed & ASC_MAX_TID) {
16609 asc_dvc->sdtr_able |= (1 << tid);
16610 }
16611 sdtr_speed >>= 4;
16612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016613
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016614 /*
16615 * Set the host maximum queuing (max. 253, min. 16) and the per device
16616 * maximum queuing (max. 63, min. 4).
16617 */
16618 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16619 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16620 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16621 /* If the value is zero, assume it is uninitialized. */
16622 if (eep_config.max_host_qng == 0) {
16623 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16624 } else {
16625 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16626 }
16627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016629 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16630 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16631 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16632 /* If the value is zero, assume it is uninitialized. */
16633 if (eep_config.max_dvc_qng == 0) {
16634 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16635 } else {
16636 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16637 }
16638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016639
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016640 /*
16641 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16642 * set 'max_dvc_qng' to 'max_host_qng'.
16643 */
16644 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16645 eep_config.max_dvc_qng = eep_config.max_host_qng;
16646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016647
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016648 /*
16649 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
16650 * values based on possibly adjusted EEPROM values.
16651 */
16652 asc_dvc->max_host_qng = eep_config.max_host_qng;
16653 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016654
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016655 /*
16656 * If the EEPROM 'termination' field is set to automatic (0), then set
16657 * the ASC_DVC_CFG 'termination' field to automatic also.
16658 *
16659 * If the termination is specified with a non-zero 'termination'
16660 * value check that a legal value is set and set the ASC_DVC_CFG
16661 * 'termination' field appropriately.
16662 */
16663 if (eep_config.termination_se == 0) {
16664 termination = 0; /* auto termination for SE */
16665 } else {
16666 /* Enable manual control with low off / high off. */
16667 if (eep_config.termination_se == 1) {
16668 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016669
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016670 /* Enable manual control with low off / high on. */
16671 } else if (eep_config.termination_se == 2) {
16672 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016673
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016674 /* Enable manual control with low on / high on. */
16675 } else if (eep_config.termination_se == 3) {
16676 termination = TERM_SE;
16677 } else {
16678 /*
16679 * The EEPROM 'termination_se' field contains a bad value.
16680 * Use automatic termination instead.
16681 */
16682 termination = 0;
16683 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16684 }
16685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016686
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016687 if (eep_config.termination_lvd == 0) {
16688 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16689 } else {
16690 /* Enable manual control with low off / high off. */
16691 if (eep_config.termination_lvd == 1) {
16692 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016693
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016694 /* Enable manual control with low off / high on. */
16695 } else if (eep_config.termination_lvd == 2) {
16696 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016697
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016698 /* Enable manual control with low on / high on. */
16699 } else if (eep_config.termination_lvd == 3) {
16700 asc_dvc->cfg->termination = termination | TERM_LVD;
16701 } else {
16702 /*
16703 * The EEPROM 'termination_lvd' field contains a bad value.
16704 * Use automatic termination instead.
16705 */
16706 asc_dvc->cfg->termination = termination;
16707 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16708 }
16709 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016710
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016711 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016712}
16713
16714/*
16715 * Read EEPROM configuration into the specified buffer.
16716 *
16717 * Return a checksum based on the EEPROM configuration read.
16718 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016719static ushort __init
Linus Torvalds1da177e2005-04-16 15:20:36 -070016720AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16721{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016722 ushort wval, chksum;
16723 ushort *wbuf;
16724 int eep_addr;
16725 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016726
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016727 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16728 wbuf = (ushort *)cfg_buf;
16729 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016730
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016731 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16732 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16733 wval = AdvReadEEPWord(iop_base, eep_addr);
16734 chksum += wval; /* Checksum is calculated from word values. */
16735 if (*charfields++) {
16736 *wbuf = le16_to_cpu(wval);
16737 } else {
16738 *wbuf = wval;
16739 }
16740 }
16741 /* Read checksum word. */
16742 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16743 wbuf++;
16744 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016746 /* Read rest of EEPROM not covered by the checksum. */
16747 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16748 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16749 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16750 if (*charfields++) {
16751 *wbuf = le16_to_cpu(*wbuf);
16752 }
16753 }
16754 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016755}
16756
16757/*
16758 * Read EEPROM configuration into the specified buffer.
16759 *
16760 * Return a checksum based on the EEPROM configuration read.
16761 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016762static ushort __init
16763AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016764{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016765 ushort wval, chksum;
16766 ushort *wbuf;
16767 int eep_addr;
16768 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016770 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16771 wbuf = (ushort *)cfg_buf;
16772 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016773
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016774 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16775 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16776 wval = AdvReadEEPWord(iop_base, eep_addr);
16777 chksum += wval; /* Checksum is calculated from word values. */
16778 if (*charfields++) {
16779 *wbuf = le16_to_cpu(wval);
16780 } else {
16781 *wbuf = wval;
16782 }
16783 }
16784 /* Read checksum word. */
16785 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16786 wbuf++;
16787 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016788
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016789 /* Read rest of EEPROM not covered by the checksum. */
16790 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16791 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16792 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16793 if (*charfields++) {
16794 *wbuf = le16_to_cpu(*wbuf);
16795 }
16796 }
16797 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016798}
16799
16800/*
16801 * Read EEPROM configuration into the specified buffer.
16802 *
16803 * Return a checksum based on the EEPROM configuration read.
16804 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016805static ushort __init
16806AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016807{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016808 ushort wval, chksum;
16809 ushort *wbuf;
16810 int eep_addr;
16811 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016812
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016813 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16814 wbuf = (ushort *)cfg_buf;
16815 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016816
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016817 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16818 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16819 wval = AdvReadEEPWord(iop_base, eep_addr);
16820 chksum += wval; /* Checksum is calculated from word values. */
16821 if (*charfields++) {
16822 *wbuf = le16_to_cpu(wval);
16823 } else {
16824 *wbuf = wval;
16825 }
16826 }
16827 /* Read checksum word. */
16828 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16829 wbuf++;
16830 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016831
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016832 /* Read rest of EEPROM not covered by the checksum. */
16833 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16834 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16835 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16836 if (*charfields++) {
16837 *wbuf = le16_to_cpu(*wbuf);
16838 }
16839 }
16840 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016841}
16842
16843/*
16844 * Read the EEPROM from specified location
16845 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016846static ushort __init AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016847{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016848 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16849 ASC_EEP_CMD_READ | eep_word_addr);
16850 AdvWaitEEPCmd(iop_base);
16851 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016852}
16853
16854/*
16855 * Wait for EEPROM command to complete
16856 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016857static void __init AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016858{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016859 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016860
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016861 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16862 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16863 ASC_EEP_CMD_DONE) {
16864 break;
16865 }
16866 DvcSleepMilliSecond(1);
16867 }
16868 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16869 0) {
16870 ASC_ASSERT(0);
16871 }
16872 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016873}
16874
16875/*
16876 * Write the EEPROM from 'cfg_buf'.
16877 */
Randy Dunlapc8360432006-06-25 05:48:40 -070016878void __init
Linus Torvalds1da177e2005-04-16 15:20:36 -070016879AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16880{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016881 ushort *wbuf;
16882 ushort addr, chksum;
16883 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016884
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016885 wbuf = (ushort *)cfg_buf;
16886 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16887 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016888
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016889 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16890 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016891
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016892 /*
16893 * Write EEPROM from word 0 to word 20.
16894 */
16895 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16896 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16897 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016898
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016899 if (*charfields++) {
16900 word = cpu_to_le16(*wbuf);
16901 } else {
16902 word = *wbuf;
16903 }
16904 chksum += *wbuf; /* Checksum is calculated from word values. */
16905 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16906 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16907 ASC_EEP_CMD_WRITE | addr);
16908 AdvWaitEEPCmd(iop_base);
16909 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16910 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016911
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016912 /*
16913 * Write EEPROM checksum at word 21.
16914 */
16915 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16916 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16917 AdvWaitEEPCmd(iop_base);
16918 wbuf++;
16919 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016920
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016921 /*
16922 * Write EEPROM OEM name at words 22 to 29.
16923 */
16924 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16925 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16926 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016927
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016928 if (*charfields++) {
16929 word = cpu_to_le16(*wbuf);
16930 } else {
16931 word = *wbuf;
16932 }
16933 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16934 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16935 ASC_EEP_CMD_WRITE | addr);
16936 AdvWaitEEPCmd(iop_base);
16937 }
16938 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16939 AdvWaitEEPCmd(iop_base);
16940 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016941}
16942
16943/*
16944 * Write the EEPROM from 'cfg_buf'.
16945 */
Randy Dunlapc8360432006-06-25 05:48:40 -070016946void __init
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016947AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016948{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016949 ushort *wbuf;
16950 ushort *charfields;
16951 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016952
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016953 wbuf = (ushort *)cfg_buf;
16954 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16955 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016956
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016957 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16958 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016959
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016960 /*
16961 * Write EEPROM from word 0 to word 20.
16962 */
16963 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16964 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16965 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016966
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016967 if (*charfields++) {
16968 word = cpu_to_le16(*wbuf);
16969 } else {
16970 word = *wbuf;
16971 }
16972 chksum += *wbuf; /* Checksum is calculated from word values. */
16973 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16974 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16975 ASC_EEP_CMD_WRITE | addr);
16976 AdvWaitEEPCmd(iop_base);
16977 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016979
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016980 /*
16981 * Write EEPROM checksum at word 21.
16982 */
16983 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16984 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16985 AdvWaitEEPCmd(iop_base);
16986 wbuf++;
16987 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016988
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016989 /*
16990 * Write EEPROM OEM name at words 22 to 29.
16991 */
16992 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16993 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16994 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016995
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016996 if (*charfields++) {
16997 word = cpu_to_le16(*wbuf);
16998 } else {
16999 word = *wbuf;
17000 }
17001 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
17002 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
17003 ASC_EEP_CMD_WRITE | addr);
17004 AdvWaitEEPCmd(iop_base);
17005 }
17006 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
17007 AdvWaitEEPCmd(iop_base);
17008 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017009}
17010
17011/*
17012 * Write the EEPROM from 'cfg_buf'.
17013 */
Randy Dunlapc8360432006-06-25 05:48:40 -070017014void __init
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017015AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017016{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017017 ushort *wbuf;
17018 ushort *charfields;
17019 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017020
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017021 wbuf = (ushort *)cfg_buf;
17022 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
17023 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017024
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017025 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
17026 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017027
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017028 /*
17029 * Write EEPROM from word 0 to word 20.
17030 */
17031 for (addr = ADV_EEP_DVC_CFG_BEGIN;
17032 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
17033 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017034
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017035 if (*charfields++) {
17036 word = cpu_to_le16(*wbuf);
17037 } else {
17038 word = *wbuf;
17039 }
17040 chksum += *wbuf; /* Checksum is calculated from word values. */
17041 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
17042 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
17043 ASC_EEP_CMD_WRITE | addr);
17044 AdvWaitEEPCmd(iop_base);
17045 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
17046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017047
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017048 /*
17049 * Write EEPROM checksum at word 21.
17050 */
17051 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
17052 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
17053 AdvWaitEEPCmd(iop_base);
17054 wbuf++;
17055 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017056
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017057 /*
17058 * Write EEPROM OEM name at words 22 to 29.
17059 */
17060 for (addr = ADV_EEP_DVC_CTL_BEGIN;
17061 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
17062 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017063
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017064 if (*charfields++) {
17065 word = cpu_to_le16(*wbuf);
17066 } else {
17067 word = *wbuf;
17068 }
17069 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
17070 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
17071 ASC_EEP_CMD_WRITE | addr);
17072 AdvWaitEEPCmd(iop_base);
17073 }
17074 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
17075 AdvWaitEEPCmd(iop_base);
17076 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017077}
17078
17079/* a_advlib.c */
17080/*
17081 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
17082 *
17083 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
17084 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
17085 * RISC to notify it a new command is ready to be executed.
17086 *
17087 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
17088 * set to SCSI_MAX_RETRY.
17089 *
17090 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
17091 * for DMA addresses or math operations are byte swapped to little-endian
17092 * order.
17093 *
17094 * Return:
17095 * ADV_SUCCESS(1) - The request was successfully queued.
17096 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
17097 * request completes.
17098 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
17099 * host IC error.
17100 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017101static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017102{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017103 ulong last_int_level;
17104 AdvPortAddr iop_base;
17105 ADV_DCNT req_size;
17106 ADV_PADDR req_paddr;
17107 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017108
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017109 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017110
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017111 /*
17112 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
17113 */
17114 if (scsiq->target_id > ADV_MAX_TID) {
17115 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
17116 scsiq->done_status = QD_WITH_ERROR;
17117 return ADV_ERROR;
17118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017119
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017120 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017121
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017122 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017123
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017124 /*
17125 * Allocate a carrier ensuring at least one carrier always
17126 * remains on the freelist and initialize fields.
17127 */
17128 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
17129 DvcLeaveCritical(last_int_level);
17130 return ADV_BUSY;
17131 }
17132 asc_dvc->carr_freelist = (ADV_CARR_T *)
17133 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
17134 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017135
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017136 /*
17137 * Set the carrier to be a stopper by setting 'next_vpa'
17138 * to the stopper value. The current stopper will be changed
17139 * below to point to the new stopper.
17140 */
17141 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017142
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017143 /*
17144 * Clear the ADV_SCSI_REQ_Q done flag.
17145 */
17146 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017147
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017148 req_size = sizeof(ADV_SCSI_REQ_Q);
17149 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
17150 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017151
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017152 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
17153 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017154
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017155 /* Wait for assertion before making little-endian */
17156 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017157
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017158 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
17159 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
17160 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017161
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017162 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
17163 /*
17164 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
17165 * order during initialization.
17166 */
17167 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017168
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017169 /*
17170 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
17171 * the microcode. The newly allocated stopper will become the new
17172 * stopper.
17173 */
17174 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017176 /*
17177 * Set the 'next_vpa' pointer for the old stopper to be the
17178 * physical address of the new stopper. The RISC can only
17179 * follow physical addresses.
17180 */
17181 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017182
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017183 /*
17184 * Set the host adapter stopper pointer to point to the new carrier.
17185 */
17186 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017187
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017188 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
17189 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17190 /*
17191 * Tickle the RISC to tell it to read its Command Queue Head pointer.
17192 */
17193 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
17194 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17195 /*
17196 * Clear the tickle value. In the ASC-3550 the RISC flag
17197 * command 'clr_tickle_a' does not work unless the host
17198 * value is cleared.
17199 */
17200 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
17201 ADV_TICKLE_NOP);
17202 }
17203 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17204 /*
17205 * Notify the RISC a carrier is ready by writing the physical
17206 * address of the new carrier stopper to the COMMA register.
17207 */
17208 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
17209 le32_to_cpu(new_carrp->carr_pa));
17210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017212 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017213
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017214 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017215}
17216
17217/*
17218 * Reset SCSI Bus and purge all outstanding requests.
17219 *
17220 * Return Value:
17221 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
17222 * ADV_FALSE(0) - Microcode command failed.
17223 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
17224 * may be hung which requires driver recovery.
17225 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017226static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017227{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017228 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017229
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017230 /*
17231 * Send the SCSI Bus Reset idle start idle command which asserts
17232 * the SCSI Bus Reset signal.
17233 */
17234 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
17235 if (status != ADV_TRUE) {
17236 return status;
17237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017238
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017239 /*
17240 * Delay for the specified SCSI Bus Reset hold time.
17241 *
17242 * The hold time delay is done on the host because the RISC has no
17243 * microsecond accurate timer.
17244 */
17245 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017246
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017247 /*
17248 * Send the SCSI Bus Reset end idle command which de-asserts
17249 * the SCSI Bus Reset signal and purges any pending requests.
17250 */
17251 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 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 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017257
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017258 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017259}
17260
17261/*
17262 * Reset chip and SCSI Bus.
17263 *
17264 * Return Value:
17265 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
17266 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
17267 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017268static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017269{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017270 int status;
17271 ushort wdtr_able, sdtr_able, tagqng_able;
17272 ushort ppr_able = 0;
17273 uchar tid, max_cmd[ADV_MAX_TID + 1];
17274 AdvPortAddr iop_base;
17275 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017276
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017277 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017278
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017279 /*
17280 * Save current per TID negotiated values.
17281 */
17282 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
17283 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
17284 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17285 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
17286 }
17287 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
17288 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
17289 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
17290 max_cmd[tid]);
17291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017292
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017293 /*
17294 * Force the AdvInitAsc3550/38C0800Driver() function to
17295 * perform a SCSI Bus Reset by clearing the BIOS signature word.
17296 * The initialization functions assumes a SCSI Bus Reset is not
17297 * needed if the BIOS signature word is present.
17298 */
17299 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
17300 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017301
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017302 /*
17303 * Stop chip and reset it.
17304 */
17305 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
17306 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
17307 DvcSleepMilliSecond(100);
17308 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
17309 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017310
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017311 /*
17312 * Reset Adv Library error code, if any, and try
17313 * re-initializing the chip.
17314 */
17315 asc_dvc->err_code = 0;
17316 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17317 status = AdvInitAsc38C1600Driver(asc_dvc);
17318 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17319 status = AdvInitAsc38C0800Driver(asc_dvc);
17320 } else {
17321 status = AdvInitAsc3550Driver(asc_dvc);
17322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017323
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017324 /* Translate initialization return value to status value. */
17325 if (status == 0) {
17326 status = ADV_TRUE;
17327 } else {
17328 status = ADV_FALSE;
17329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017330
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017331 /*
17332 * Restore the BIOS signature word.
17333 */
17334 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017335
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017336 /*
17337 * Restore per TID negotiated values.
17338 */
17339 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
17340 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
17341 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17342 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
17343 }
17344 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
17345 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
17346 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
17347 max_cmd[tid]);
17348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017349
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017350 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017351}
17352
17353/*
17354 * Adv Library Interrupt Service Routine
17355 *
17356 * This function is called by a driver's interrupt service routine.
17357 * The function disables and re-enables interrupts.
17358 *
17359 * When a microcode idle command is completed, the ADV_DVC_VAR
17360 * 'idle_cmd_done' field is set to ADV_TRUE.
17361 *
17362 * Note: AdvISR() can be called when interrupts are disabled or even
17363 * when there is no hardware interrupt condition present. It will
17364 * always check for completed idle commands and microcode requests.
17365 * This is an important feature that shouldn't be changed because it
17366 * allows commands to be completed from polling mode loops.
17367 *
17368 * Return:
17369 * ADV_TRUE(1) - interrupt was pending
17370 * ADV_FALSE(0) - no interrupt was pending
17371 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017372static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017373{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017374 AdvPortAddr iop_base;
17375 uchar int_stat;
17376 ushort target_bit;
17377 ADV_CARR_T *free_carrp;
17378 ADV_VADDR irq_next_vpa;
17379 int flags;
17380 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017381
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017382 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017383
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017384 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017386 /* Reading the register clears the interrupt. */
17387 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017388
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017389 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
17390 ADV_INTR_STATUS_INTRC)) == 0) {
17391 DvcLeaveCritical(flags);
17392 return ADV_FALSE;
17393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017394
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017395 /*
17396 * Notify the driver of an asynchronous microcode condition by
17397 * calling the ADV_DVC_VAR.async_callback function. The function
17398 * is passed the microcode ASC_MC_INTRB_CODE byte value.
17399 */
17400 if (int_stat & ADV_INTR_STATUS_INTRB) {
17401 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017402
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017403 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017404
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017405 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
17406 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17407 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
17408 asc_dvc->carr_pending_cnt != 0) {
17409 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
17410 ADV_TICKLE_A);
17411 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17412 AdvWriteByteRegister(iop_base,
17413 IOPB_TICKLE,
17414 ADV_TICKLE_NOP);
17415 }
17416 }
17417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017418
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017419 if (asc_dvc->async_callback != 0) {
17420 (*asc_dvc->async_callback) (asc_dvc, intrb_code);
17421 }
17422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017423
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017424 /*
17425 * Check if the IRQ stopper carrier contains a completed request.
17426 */
17427 while (((irq_next_vpa =
17428 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
17429 /*
17430 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
17431 * The RISC will have set 'areq_vpa' to a virtual address.
17432 *
17433 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
17434 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
17435 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
17436 * in AdvExeScsiQueue().
17437 */
17438 scsiq = (ADV_SCSI_REQ_Q *)
17439 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017441 /*
17442 * Request finished with good status and the queue was not
17443 * DMAed to host memory by the firmware. Set all status fields
17444 * to indicate good status.
17445 */
17446 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
17447 scsiq->done_status = QD_NO_ERROR;
17448 scsiq->host_status = scsiq->scsi_status = 0;
17449 scsiq->data_cnt = 0L;
17450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017451
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017452 /*
17453 * Advance the stopper pointer to the next carrier
17454 * ignoring the lower four bits. Free the previous
17455 * stopper carrier.
17456 */
17457 free_carrp = asc_dvc->irq_sp;
17458 asc_dvc->irq_sp = (ADV_CARR_T *)
17459 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017460
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017461 free_carrp->next_vpa =
17462 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
17463 asc_dvc->carr_freelist = free_carrp;
17464 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017465
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017466 ASC_ASSERT(scsiq != NULL);
17467 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017468
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017469 /*
17470 * Clear request microcode control flag.
17471 */
17472 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017473
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017474 /*
17475 * If the command that completed was a SCSI INQUIRY and
17476 * LUN 0 was sent the command, then process the INQUIRY
17477 * command information for the device.
17478 *
17479 * Note: If data returned were either VPD or CmdDt data,
17480 * don't process the INQUIRY command information for
17481 * the device, otherwise may erroneously set *_able bits.
17482 */
17483 if (scsiq->done_status == QD_NO_ERROR &&
17484 scsiq->cdb[0] == INQUIRY &&
17485 scsiq->target_lun == 0 &&
17486 (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
17487 == ADV_INQ_RTN_STD_INQUIRY_DATA) {
17488 AdvInquiryHandling(asc_dvc, scsiq);
17489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017490
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017491 /*
17492 * Notify the driver of the completed request by passing
17493 * the ADV_SCSI_REQ_Q pointer to its callback function.
17494 */
17495 scsiq->a_flag |= ADV_SCSIQ_DONE;
17496 (*asc_dvc->isr_callback) (asc_dvc, scsiq);
17497 /*
17498 * Note: After the driver callback function is called, 'scsiq'
17499 * can no longer be referenced.
17500 *
17501 * Fall through and continue processing other completed
17502 * requests...
17503 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017504
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017505 /*
17506 * Disable interrupts again in case the driver inadvertently
17507 * enabled interrupts in its callback function.
17508 *
17509 * The DvcEnterCritical() return value is ignored, because
17510 * the 'flags' saved when AdvISR() was first entered will be
17511 * used to restore the interrupt flag on exit.
17512 */
17513 (void)DvcEnterCritical();
17514 }
17515 DvcLeaveCritical(flags);
17516 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017517}
17518
17519/*
17520 * Send an idle command to the chip and wait for completion.
17521 *
17522 * Command completion is polled for once per microsecond.
17523 *
17524 * The function can be called from anywhere including an interrupt handler.
17525 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
17526 * functions to prevent reentrancy.
17527 *
17528 * Return Values:
17529 * ADV_TRUE - command completed successfully
17530 * ADV_FALSE - command failed
17531 * ADV_ERROR - command timed out
17532 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017533static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070017534AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017535 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017536{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017537 ulong last_int_level;
17538 int result;
17539 ADV_DCNT i, j;
17540 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017541
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017542 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017543
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017544 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017545
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017546 /*
17547 * Clear the idle command status which is set by the microcode
17548 * to a non-zero value to indicate when the command is completed.
17549 * The non-zero result is one of the IDLE_CMD_STATUS_* values
17550 * defined in a_advlib.h.
17551 */
17552 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017553
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017554 /*
17555 * Write the idle command value after the idle command parameter
17556 * has been written to avoid a race condition. If the order is not
17557 * followed, the microcode may process the idle command before the
17558 * parameters have been written to LRAM.
17559 */
17560 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
17561 cpu_to_le32(idle_cmd_parameter));
17562 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017563
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017564 /*
17565 * Tickle the RISC to tell it to process the idle command.
17566 */
17567 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
17568 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17569 /*
17570 * Clear the tickle value. In the ASC-3550 the RISC flag
17571 * command 'clr_tickle_b' does not work unless the host
17572 * value is cleared.
17573 */
17574 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
17575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017577 /* Wait for up to 100 millisecond for the idle command to timeout. */
17578 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
17579 /* Poll once each microsecond for command completion. */
17580 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
17581 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
17582 result);
17583 if (result != 0) {
17584 DvcLeaveCritical(last_int_level);
17585 return result;
17586 }
17587 DvcDelayMicroSecond(asc_dvc, (ushort)1);
17588 }
17589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017590
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017591 ASC_ASSERT(0); /* The idle command should never timeout. */
17592 DvcLeaveCritical(last_int_level);
17593 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017594}
17595
17596/*
17597 * Inquiry Information Byte 7 Handling
17598 *
17599 * Handle SCSI Inquiry Command information for a device by setting
17600 * microcode operating variables that affect WDTR, SDTR, and Tag
17601 * Queuing.
17602 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017603static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017604{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017605 AdvPortAddr iop_base;
17606 uchar tid;
17607 ADV_SCSI_INQUIRY *inq;
17608 ushort tidmask;
17609 ushort cfg_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017610
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017611 /*
17612 * AdvInquiryHandling() requires up to INQUIRY information Byte 7
17613 * to be available.
17614 *
17615 * If less than 8 bytes of INQUIRY information were requested or less
17616 * than 8 bytes were transferred, then return. cdb[4] is the request
17617 * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
17618 * microcode to the transfer residual count.
17619 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017620
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017621 if (scsiq->cdb[4] < 8 ||
17622 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) {
17623 return;
17624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017625
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017626 iop_base = asc_dvc->iop_base;
17627 tid = scsiq->target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017629 inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017630
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017631 /*
17632 * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
17633 */
17634 if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) {
17635 return;
17636 } else {
17637 /*
17638 * INQUIRY Byte 7 Handling
17639 *
17640 * Use a device's INQUIRY byte 7 to determine whether it
17641 * supports WDTR, SDTR, and Tag Queuing. If the feature
17642 * is enabled in the EEPROM and the device supports the
17643 * feature, then enable it in the microcode.
17644 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017645
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017646 tidmask = ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017647
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017648 /*
17649 * Wide Transfers
17650 *
17651 * If the EEPROM enabled WDTR for the device and the device
17652 * supports wide bus (16 bit) transfers, then turn on the
17653 * device's 'wdtr_able' bit and write the new value to the
17654 * microcode.
17655 */
17656 if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) {
17657 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
17658 if ((cfg_word & tidmask) == 0) {
17659 cfg_word |= tidmask;
17660 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
17661 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017662
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017663 /*
17664 * Clear the microcode "SDTR negotiation" and "WDTR
17665 * negotiation" done indicators for the target to cause
17666 * it to negotiate with the new setting set above.
17667 * WDTR when accepted causes the target to enter
17668 * asynchronous mode, so SDTR must be negotiated.
17669 */
17670 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17671 cfg_word);
17672 cfg_word &= ~tidmask;
17673 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17674 cfg_word);
17675 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE,
17676 cfg_word);
17677 cfg_word &= ~tidmask;
17678 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE,
17679 cfg_word);
17680 }
17681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017682
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017683 /*
17684 * Synchronous Transfers
17685 *
17686 * If the EEPROM enabled SDTR for the device and the device
17687 * supports synchronous transfers, then turn on the device's
17688 * 'sdtr_able' bit. Write the new value to the microcode.
17689 */
17690 if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) {
17691 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
17692 if ((cfg_word & tidmask) == 0) {
17693 cfg_word |= tidmask;
17694 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
17695 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017696
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017697 /*
17698 * Clear the microcode "SDTR negotiation" done indicator
17699 * for the target to cause it to negotiate with the new
17700 * setting set above.
17701 */
17702 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17703 cfg_word);
17704 cfg_word &= ~tidmask;
17705 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17706 cfg_word);
17707 }
17708 }
17709 /*
17710 * If the Inquiry data included enough space for the SPI-3
17711 * Clocking field, then check if DT mode is supported.
17712 */
17713 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
17714 (scsiq->cdb[4] >= 57 ||
17715 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) {
17716 /*
17717 * PPR (Parallel Protocol Request) Capable
17718 *
17719 * If the device supports DT mode, then it must be PPR capable.
17720 * The PPR message will be used in place of the SDTR and WDTR
17721 * messages to negotiate synchronous speed and offset, transfer
17722 * width, and protocol options.
17723 */
17724 if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) {
17725 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE,
17726 asc_dvc->ppr_able);
17727 asc_dvc->ppr_able |= tidmask;
17728 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE,
17729 asc_dvc->ppr_able);
17730 }
17731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017732
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017733 /*
17734 * If the EEPROM enabled Tag Queuing for the device and the
17735 * device supports Tag Queueing, then turn on the device's
17736 * 'tagqng_enable' bit in the microcode and set the microcode
17737 * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
17738 * value.
17739 *
17740 * Tag Queuing is disabled for the BIOS which runs in polled
17741 * mode and would see no benefit from Tag Queuing. Also by
17742 * disabling Tag Queuing in the BIOS devices with Tag Queuing
17743 * bugs will at least work with the BIOS.
17744 */
17745 if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) {
17746 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
17747 cfg_word |= tidmask;
17748 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
17749 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017750
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017751 AdvWriteByteLram(iop_base,
17752 ASC_MC_NUMBER_OF_MAX_CMD + tid,
17753 asc_dvc->max_dvc_qng);
17754 }
17755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017756}
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017757
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017758static struct Scsi_Host *__devinit
17759advansys_board_found(int iop, struct device *dev, int bus_type)
17760{
17761 struct Scsi_Host *shost;
17762 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
17763 asc_board_t *boardp;
17764 ASC_DVC_VAR *asc_dvc_varp = NULL;
17765 ADV_DVC_VAR *adv_dvc_varp = NULL;
17766 adv_sgblk_t *sgp = NULL;
17767 int share_irq = FALSE;
17768 int iolen = 0;
17769 ADV_PADDR pci_memory_address;
17770 int warn_code, err_code;
17771 int ret;
17772
17773 /*
17774 * Adapter found.
17775 *
17776 * Register the adapter, get its configuration, and
17777 * initialize it.
17778 */
17779 ASC_DBG(2, "advansys_board_found: scsi_register()\n");
17780 shost = scsi_register(&driver_template, sizeof(asc_board_t));
17781
17782 if (!shost)
17783 return NULL;
17784
17785 /* Save a pointer to the Scsi_Host of each board found. */
17786 asc_host[asc_board_count++] = shost;
17787
17788 /* Initialize private per board data */
17789 boardp = ASC_BOARDP(shost);
17790 memset(boardp, 0, sizeof(asc_board_t));
17791 boardp->id = asc_board_count - 1;
17792
17793 /* Initialize spinlock. */
17794 spin_lock_init(&boardp->lock);
17795
17796 /*
17797 * Handle both narrow and wide boards.
17798 *
17799 * If a Wide board was detected, set the board structure
17800 * wide board flag. Set-up the board structure based on
17801 * the board type.
17802 */
17803#ifdef CONFIG_PCI
17804 if (bus_type == ASC_IS_PCI &&
17805 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17806 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17807 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17808 boardp->flags |= ASC_IS_WIDE_BOARD;
17809 }
17810#endif /* CONFIG_PCI */
17811
17812 if (ASC_NARROW_BOARD(boardp)) {
17813 ASC_DBG(1, "advansys_board_found: narrow board\n");
17814 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17815 asc_dvc_varp->bus_type = bus_type;
17816 asc_dvc_varp->drv_ptr = boardp;
17817 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17818 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17819 asc_dvc_varp->iop_base = iop;
17820 asc_dvc_varp->isr_callback = asc_isr_callback;
17821 } else {
17822 ASC_DBG(1, "advansys_board_found: wide board\n");
17823 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17824 adv_dvc_varp->drv_ptr = boardp;
17825 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
17826 adv_dvc_varp->isr_callback = adv_isr_callback;
17827 adv_dvc_varp->async_callback = adv_async_callback;
17828#ifdef CONFIG_PCI
17829 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17830 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17831 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17832 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17833 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17834 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17835 } else {
17836 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17837 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17838 }
17839#endif /* CONFIG_PCI */
17840
17841 /*
17842 * Map the board's registers into virtual memory for
17843 * PCI slave access. Only memory accesses are used to
17844 * access the board's registers.
17845 *
17846 * Note: The PCI register base address is not always
17847 * page aligned, but the address passed to ioremap()
17848 * must be page aligned. It is guaranteed that the
17849 * PCI register base address will not cross a page
17850 * boundary.
17851 */
17852 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17853 iolen = ADV_3550_IOLEN;
17854 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17855 iolen = ADV_38C0800_IOLEN;
17856 } else {
17857 iolen = ADV_38C1600_IOLEN;
17858 }
17859#ifdef CONFIG_PCI
17860 pci_memory_address = pci_resource_start(pdev, 1);
17861 ASC_DBG1(1,
17862 "advansys_board_found: pci_memory_address: 0x%lx\n",
17863 (ulong)pci_memory_address);
17864 if ((boardp->ioremap_addr =
17865 ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
17866 ASC_PRINT3
17867 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
17868 boardp->id, pci_memory_address, iolen);
17869 scsi_unregister(shost);
17870 asc_board_count--;
17871 return NULL;
17872 }
17873 ASC_DBG1(1,
17874 "advansys_board_found: ioremap_addr: 0x%lx\n",
17875 (ulong)boardp->ioremap_addr);
17876 adv_dvc_varp->iop_base = (AdvPortAddr)
17877 (boardp->ioremap_addr +
17878 (pci_memory_address - (pci_memory_address & PAGE_MASK)));
17879 ASC_DBG1(1,
17880 "advansys_board_found: iop_base: 0x%lx\n",
17881 adv_dvc_varp->iop_base);
17882#endif /* CONFIG_PCI */
17883
17884 /*
17885 * Even though it isn't used to access wide boards, other
17886 * than for the debug line below, save I/O Port address so
17887 * that it can be reported.
17888 */
17889 boardp->ioport = iop;
17890
17891 ASC_DBG2(1,
17892 "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
17893 (ushort)inp(iop + 1), (ushort)inpw(iop));
17894 }
17895
17896#ifdef CONFIG_PROC_FS
17897 /*
17898 * Allocate buffer for printing information from
17899 * /proc/scsi/advansys/[0...].
17900 */
17901 if ((boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
17902 ASC_PRINT3
17903 ("advansys_board_found: board %d: kmalloc(%d, %d) returned NULL\n",
17904 boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
17905 scsi_unregister(shost);
17906 asc_board_count--;
17907 return NULL;
17908 }
17909#endif /* CONFIG_PROC_FS */
17910
17911 if (ASC_NARROW_BOARD(boardp)) {
17912 asc_dvc_varp->cfg->dev = dev;
17913 /*
17914 * Set the board bus type and PCI IRQ before
17915 * calling AscInitGetConfig().
17916 */
17917 switch (asc_dvc_varp->bus_type) {
17918#ifdef CONFIG_ISA
17919 case ASC_IS_ISA:
17920 shost->unchecked_isa_dma = TRUE;
17921 share_irq = FALSE;
17922 break;
17923 case ASC_IS_VL:
17924 shost->unchecked_isa_dma = FALSE;
17925 share_irq = FALSE;
17926 break;
17927 case ASC_IS_EISA:
17928 shost->unchecked_isa_dma = FALSE;
17929 share_irq = TRUE;
17930 break;
17931#endif /* CONFIG_ISA */
17932#ifdef CONFIG_PCI
17933 case ASC_IS_PCI:
17934 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
17935 asc_dvc_varp->cfg->pci_slot_info =
17936 ASC_PCI_MKID(pdev->bus->number,
17937 PCI_SLOT(pdev->devfn),
17938 PCI_FUNC(pdev->devfn));
17939 shost->unchecked_isa_dma = FALSE;
17940 share_irq = TRUE;
17941 break;
17942#endif /* CONFIG_PCI */
17943 default:
17944 ASC_PRINT2
17945 ("advansys_board_found: board %d: unknown adapter type: %d\n",
17946 boardp->id, asc_dvc_varp->bus_type);
17947 shost->unchecked_isa_dma = TRUE;
17948 share_irq = FALSE;
17949 break;
17950 }
17951 } else {
17952 adv_dvc_varp->cfg->dev = dev;
17953 /*
17954 * For Wide boards set PCI information before calling
17955 * AdvInitGetConfig().
17956 */
17957#ifdef CONFIG_PCI
17958 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
17959 adv_dvc_varp->cfg->pci_slot_info =
17960 ASC_PCI_MKID(pdev->bus->number,
17961 PCI_SLOT(pdev->devfn),
17962 PCI_FUNC(pdev->devfn));
17963 shost->unchecked_isa_dma = FALSE;
17964 share_irq = TRUE;
17965#endif /* CONFIG_PCI */
17966 }
17967
17968 /*
17969 * Read the board configuration.
17970 */
17971 if (ASC_NARROW_BOARD(boardp)) {
17972 /*
17973 * NOTE: AscInitGetConfig() may change the board's
17974 * bus_type value. The bus_type value should no
17975 * longer be used. If the bus_type field must be
17976 * referenced only use the bit-wise AND operator "&".
17977 */
17978 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
17979 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
17980 case 0: /* No error */
17981 break;
17982 case ASC_WARN_IO_PORT_ROTATE:
17983 ASC_PRINT1
17984 ("AscInitGetConfig: board %d: I/O port address modified\n",
17985 boardp->id);
17986 break;
17987 case ASC_WARN_AUTO_CONFIG:
17988 ASC_PRINT1
17989 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
17990 boardp->id);
17991 break;
17992 case ASC_WARN_EEPROM_CHKSUM:
17993 ASC_PRINT1
17994 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
17995 boardp->id);
17996 break;
17997 case ASC_WARN_IRQ_MODIFIED:
17998 ASC_PRINT1
17999 ("AscInitGetConfig: board %d: IRQ modified\n",
18000 boardp->id);
18001 break;
18002 case ASC_WARN_CMD_QNG_CONFLICT:
18003 ASC_PRINT1
18004 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
18005 boardp->id);
18006 break;
18007 default:
18008 ASC_PRINT2
18009 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
18010 boardp->id, ret);
18011 break;
18012 }
18013 if ((err_code = asc_dvc_varp->err_code) != 0) {
18014 ASC_PRINT3
18015 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
18016 boardp->id,
18017 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
18018 }
18019 } else {
18020 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
18021 if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
18022 ASC_PRINT2
18023 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
18024 boardp->id, ret);
18025 }
18026 if ((err_code = adv_dvc_varp->err_code) != 0) {
18027 ASC_PRINT2
18028 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
18029 boardp->id, adv_dvc_varp->err_code);
18030 }
18031 }
18032
18033 if (err_code != 0) {
18034#ifdef CONFIG_PROC_FS
18035 kfree(boardp->prtbuf);
18036#endif /* CONFIG_PROC_FS */
18037 scsi_unregister(shost);
18038 asc_board_count--;
18039 return NULL;
18040 }
18041
18042 /*
18043 * Save the EEPROM configuration so that it can be displayed
18044 * from /proc/scsi/advansys/[0...].
18045 */
18046 if (ASC_NARROW_BOARD(boardp)) {
18047
18048 ASCEEP_CONFIG *ep;
18049
18050 /*
18051 * Set the adapter's target id bit in the 'init_tidmask' field.
18052 */
18053 boardp->init_tidmask |=
18054 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
18055
18056 /*
18057 * Save EEPROM settings for the board.
18058 */
18059 ep = &boardp->eep_config.asc_eep;
18060
18061 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
18062 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
18063 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
18064 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
18065 ep->start_motor = asc_dvc_varp->start_motor;
18066 ep->cntl = asc_dvc_varp->dvc_cntl;
18067 ep->no_scam = asc_dvc_varp->no_scam;
18068 ep->max_total_qng = asc_dvc_varp->max_total_qng;
18069 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
18070 /* 'max_tag_qng' is set to the same value for every device. */
18071 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
18072 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
18073 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
18074 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
18075 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
18076 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
18077 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
18078
18079 /*
18080 * Modify board configuration.
18081 */
18082 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
18083 switch (ret = AscInitSetConfig(asc_dvc_varp)) {
18084 case 0: /* No error. */
18085 break;
18086 case ASC_WARN_IO_PORT_ROTATE:
18087 ASC_PRINT1
18088 ("AscInitSetConfig: board %d: I/O port address modified\n",
18089 boardp->id);
18090 break;
18091 case ASC_WARN_AUTO_CONFIG:
18092 ASC_PRINT1
18093 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
18094 boardp->id);
18095 break;
18096 case ASC_WARN_EEPROM_CHKSUM:
18097 ASC_PRINT1
18098 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
18099 boardp->id);
18100 break;
18101 case ASC_WARN_IRQ_MODIFIED:
18102 ASC_PRINT1
18103 ("AscInitSetConfig: board %d: IRQ modified\n",
18104 boardp->id);
18105 break;
18106 case ASC_WARN_CMD_QNG_CONFLICT:
18107 ASC_PRINT1
18108 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
18109 boardp->id);
18110 break;
18111 default:
18112 ASC_PRINT2
18113 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
18114 boardp->id, ret);
18115 break;
18116 }
18117 if (asc_dvc_varp->err_code != 0) {
18118 ASC_PRINT3
18119 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
18120 boardp->id,
18121 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
18122#ifdef CONFIG_PROC_FS
18123 kfree(boardp->prtbuf);
18124#endif /* CONFIG_PROC_FS */
18125 scsi_unregister(shost);
18126 asc_board_count--;
18127 return NULL;
18128 }
18129
18130 /*
18131 * Finish initializing the 'Scsi_Host' structure.
18132 */
18133 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
18134 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
18135 shost->irq = asc_dvc_varp->irq_no;
18136 }
18137 } else {
18138 ADVEEP_3550_CONFIG *ep_3550;
18139 ADVEEP_38C0800_CONFIG *ep_38C0800;
18140 ADVEEP_38C1600_CONFIG *ep_38C1600;
18141
18142 /*
18143 * Save Wide EEP Configuration Information.
18144 */
18145 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
18146 ep_3550 = &boardp->eep_config.adv_3550_eep;
18147
18148 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
18149 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
18150 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18151 ep_3550->termination = adv_dvc_varp->cfg->termination;
18152 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
18153 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
18154 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
18155 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
18156 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
18157 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
18158 ep_3550->start_motor = adv_dvc_varp->start_motor;
18159 ep_3550->scsi_reset_delay =
18160 adv_dvc_varp->scsi_reset_wait;
18161 ep_3550->serial_number_word1 =
18162 adv_dvc_varp->cfg->serial1;
18163 ep_3550->serial_number_word2 =
18164 adv_dvc_varp->cfg->serial2;
18165 ep_3550->serial_number_word3 =
18166 adv_dvc_varp->cfg->serial3;
18167 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
18168 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
18169
18170 ep_38C0800->adapter_scsi_id =
18171 adv_dvc_varp->chip_scsi_id;
18172 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
18173 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18174 ep_38C0800->termination_lvd =
18175 adv_dvc_varp->cfg->termination;
18176 ep_38C0800->disc_enable =
18177 adv_dvc_varp->cfg->disc_enable;
18178 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
18179 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
18180 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
18181 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
18182 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
18183 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
18184 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
18185 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
18186 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
18187 ep_38C0800->scsi_reset_delay =
18188 adv_dvc_varp->scsi_reset_wait;
18189 ep_38C0800->serial_number_word1 =
18190 adv_dvc_varp->cfg->serial1;
18191 ep_38C0800->serial_number_word2 =
18192 adv_dvc_varp->cfg->serial2;
18193 ep_38C0800->serial_number_word3 =
18194 adv_dvc_varp->cfg->serial3;
18195 } else {
18196 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
18197
18198 ep_38C1600->adapter_scsi_id =
18199 adv_dvc_varp->chip_scsi_id;
18200 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
18201 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18202 ep_38C1600->termination_lvd =
18203 adv_dvc_varp->cfg->termination;
18204 ep_38C1600->disc_enable =
18205 adv_dvc_varp->cfg->disc_enable;
18206 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
18207 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
18208 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
18209 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
18210 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
18211 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
18212 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
18213 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
18214 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
18215 ep_38C1600->scsi_reset_delay =
18216 adv_dvc_varp->scsi_reset_wait;
18217 ep_38C1600->serial_number_word1 =
18218 adv_dvc_varp->cfg->serial1;
18219 ep_38C1600->serial_number_word2 =
18220 adv_dvc_varp->cfg->serial2;
18221 ep_38C1600->serial_number_word3 =
18222 adv_dvc_varp->cfg->serial3;
18223 }
18224
18225 /*
18226 * Set the adapter's target id bit in the 'init_tidmask' field.
18227 */
18228 boardp->init_tidmask |=
18229 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
18230
18231 /*
18232 * Finish initializing the 'Scsi_Host' structure.
18233 */
18234 shost->irq = adv_dvc_varp->irq_no;
18235 }
18236
18237 /*
18238 * Channels are numbered beginning with 0. For AdvanSys one host
18239 * structure supports one channel. Multi-channel boards have a
18240 * separate host structure for each channel.
18241 */
18242 shost->max_channel = 0;
18243 if (ASC_NARROW_BOARD(boardp)) {
18244 shost->max_id = ASC_MAX_TID + 1;
18245 shost->max_lun = ASC_MAX_LUN + 1;
18246
18247 shost->io_port = asc_dvc_varp->iop_base;
18248 boardp->asc_n_io_port = ASC_IOADR_GAP;
18249 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
18250
18251 /* Set maximum number of queues the adapter can handle. */
18252 shost->can_queue = asc_dvc_varp->max_total_qng;
18253 } else {
18254 shost->max_id = ADV_MAX_TID + 1;
18255 shost->max_lun = ADV_MAX_LUN + 1;
18256
18257 /*
18258 * Save the I/O Port address and length even though
18259 * I/O ports are not used to access Wide boards.
18260 * Instead the Wide boards are accessed with
18261 * PCI Memory Mapped I/O.
18262 */
18263 shost->io_port = iop;
18264 boardp->asc_n_io_port = iolen;
18265
18266 shost->this_id = adv_dvc_varp->chip_scsi_id;
18267
18268 /* Set maximum number of queues the adapter can handle. */
18269 shost->can_queue = adv_dvc_varp->max_host_qng;
18270 }
18271
18272 /*
18273 * 'n_io_port' currently is one byte.
18274 *
18275 * Set a value to 'n_io_port', but never referenced it because
18276 * it may be truncated.
18277 */
18278 shost->n_io_port = boardp->asc_n_io_port <= 255 ?
18279 boardp->asc_n_io_port : 255;
18280
18281 /*
18282 * Following v1.3.89, 'cmd_per_lun' is no longer needed
18283 * and should be set to zero.
18284 *
18285 * But because of a bug introduced in v1.3.89 if the driver is
18286 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
18287 * SCSI function 'allocate_device' will panic. To allow the driver
18288 * to work as a module in these kernels set 'cmd_per_lun' to 1.
18289 *
18290 * Note: This is wrong. cmd_per_lun should be set to the depth
18291 * you want on untagged devices always.
18292 #ifdef MODULE
18293 */
18294 shost->cmd_per_lun = 1;
18295/* #else
18296 shost->cmd_per_lun = 0;
18297#endif */
18298
18299 /*
18300 * Set the maximum number of scatter-gather elements the
18301 * adapter can handle.
18302 */
18303 if (ASC_NARROW_BOARD(boardp)) {
18304 /*
18305 * Allow two commands with 'sg_tablesize' scatter-gather
18306 * elements to be executed simultaneously. This value is
18307 * the theoretical hardware limit. It may be decreased
18308 * below.
18309 */
18310 shost->sg_tablesize =
18311 (((asc_dvc_varp->max_total_qng - 2) / 2) *
18312 ASC_SG_LIST_PER_Q) + 1;
18313 } else {
18314 shost->sg_tablesize = ADV_MAX_SG_LIST;
18315 }
18316
18317 /*
18318 * The value of 'sg_tablesize' can not exceed the SCSI
18319 * mid-level driver definition of SG_ALL. SG_ALL also
18320 * must not be exceeded, because it is used to define the
18321 * size of the scatter-gather table in 'struct asc_sg_head'.
18322 */
18323 if (shost->sg_tablesize > SG_ALL) {
18324 shost->sg_tablesize = SG_ALL;
18325 }
18326
18327 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
18328
18329 /* BIOS start address. */
18330 if (ASC_NARROW_BOARD(boardp)) {
18331 shost->base = ((ulong)
18332 AscGetChipBiosAddress(asc_dvc_varp->
18333 iop_base,
18334 asc_dvc_varp->bus_type));
18335 } else {
18336 /*
18337 * Fill-in BIOS board variables. The Wide BIOS saves
18338 * information in LRAM that is used by the driver.
18339 */
18340 AdvReadWordLram(adv_dvc_varp->iop_base,
18341 BIOS_SIGNATURE, boardp->bios_signature);
18342 AdvReadWordLram(adv_dvc_varp->iop_base,
18343 BIOS_VERSION, boardp->bios_version);
18344 AdvReadWordLram(adv_dvc_varp->iop_base,
18345 BIOS_CODESEG, boardp->bios_codeseg);
18346 AdvReadWordLram(adv_dvc_varp->iop_base,
18347 BIOS_CODELEN, boardp->bios_codelen);
18348
18349 ASC_DBG2(1,
18350 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
18351 boardp->bios_signature, boardp->bios_version);
18352
18353 ASC_DBG2(1,
18354 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
18355 boardp->bios_codeseg, boardp->bios_codelen);
18356
18357 /*
18358 * If the BIOS saved a valid signature, then fill in
18359 * the BIOS code segment base address.
18360 */
18361 if (boardp->bios_signature == 0x55AA) {
18362 /*
18363 * Convert x86 realmode code segment to a linear
18364 * address by shifting left 4.
18365 */
18366 shost->base = ((ulong)boardp->bios_codeseg << 4);
18367 } else {
18368 shost->base = 0;
18369 }
18370 }
18371
18372 /*
18373 * Register Board Resources - I/O Port, DMA, IRQ
18374 */
18375
18376 /*
18377 * Register I/O port range.
18378 *
18379 * For Wide boards the I/O ports are not used to access
18380 * the board, but request the region anyway.
18381 *
18382 * 'shost->n_io_port' is not referenced, because it may be truncated.
18383 */
18384 ASC_DBG2(2,
18385 "advansys_board_found: request_region port 0x%lx, len 0x%x\n",
18386 (ulong)shost->io_port, boardp->asc_n_io_port);
18387 if (request_region(shost->io_port, boardp->asc_n_io_port,
18388 "advansys") == NULL) {
18389 ASC_PRINT3
18390 ("advansys_board_found: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
18391 boardp->id, (ulong)shost->io_port, boardp->asc_n_io_port);
18392#ifdef CONFIG_PROC_FS
18393 kfree(boardp->prtbuf);
18394#endif /* CONFIG_PROC_FS */
18395 scsi_unregister(shost);
18396 asc_board_count--;
18397 return NULL;
18398 }
18399
18400 /* Register DMA Channel for Narrow boards. */
18401 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
18402#ifdef CONFIG_ISA
18403 if (ASC_NARROW_BOARD(boardp)) {
18404 /* Register DMA channel for ISA bus. */
18405 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
18406 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
18407 if ((ret =
18408 request_dma(shost->dma_channel, "advansys")) != 0) {
18409 ASC_PRINT3
18410 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
18411 boardp->id, shost->dma_channel, ret);
18412 release_region(shost->io_port,
18413 boardp->asc_n_io_port);
18414#ifdef CONFIG_PROC_FS
18415 kfree(boardp->prtbuf);
18416#endif /* CONFIG_PROC_FS */
18417 scsi_unregister(shost);
18418 asc_board_count--;
18419 return NULL;
18420 }
18421 AscEnableIsaDma(shost->dma_channel);
18422 }
18423 }
18424#endif /* CONFIG_ISA */
18425
18426 /* Register IRQ Number. */
18427 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
18428 /*
18429 * If request_irq() fails with the IRQF_DISABLED flag set,
18430 * then try again without the IRQF_DISABLED flag set. This
18431 * allows IRQ sharing to work even with other drivers that
18432 * do not set the IRQF_DISABLED flag.
18433 *
18434 * If IRQF_DISABLED is not set, then interrupts are enabled
18435 * before the driver interrupt function is called.
18436 */
18437 if (((ret = request_irq(shost->irq, advansys_interrupt,
18438 IRQF_DISABLED | (share_irq ==
18439 TRUE ?
18440 IRQF_SHARED :
18441 0), "advansys", boardp)) != 0)
18442 &&
18443 ((ret =
18444 request_irq(shost->irq, advansys_interrupt,
18445 (share_irq == TRUE ? IRQF_SHARED : 0),
18446 "advansys", boardp)) != 0)) {
18447 if (ret == -EBUSY) {
18448 ASC_PRINT2
18449 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
18450 boardp->id, shost->irq);
18451 } else if (ret == -EINVAL) {
18452 ASC_PRINT2
18453 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
18454 boardp->id, shost->irq);
18455 } else {
18456 ASC_PRINT3
18457 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
18458 boardp->id, shost->irq, ret);
18459 }
18460 release_region(shost->io_port, boardp->asc_n_io_port);
18461 iounmap(boardp->ioremap_addr);
18462 if (shost->dma_channel != NO_ISA_DMA) {
18463 free_dma(shost->dma_channel);
18464 }
18465#ifdef CONFIG_PROC_FS
18466 kfree(boardp->prtbuf);
18467#endif /* CONFIG_PROC_FS */
18468 scsi_unregister(shost);
18469 asc_board_count--;
18470 return NULL;
18471 }
18472
18473 /*
18474 * Initialize board RISC chip and enable interrupts.
18475 */
18476 if (ASC_NARROW_BOARD(boardp)) {
18477 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
18478 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
18479 err_code = asc_dvc_varp->err_code;
18480
18481 if (warn_code || err_code) {
18482 ASC_PRINT4
18483 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
18484 boardp->id,
18485 asc_dvc_varp->init_state, warn_code, err_code);
18486 }
18487 } else {
18488 ADV_CARR_T *carrp;
18489 int req_cnt = 0;
18490 adv_req_t *reqp = NULL;
18491 int sg_cnt = 0;
18492
18493 /*
18494 * Allocate buffer carrier structures. The total size
18495 * is about 4 KB, so allocate all at once.
18496 */
18497 carrp = (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
18498 ASC_DBG1(1, "advansys_board_found: carrp 0x%lx\n", (ulong)carrp);
18499
18500 if (carrp == NULL) {
18501 goto kmalloc_error;
18502 }
18503
18504 /*
18505 * Allocate up to 'max_host_qng' request structures for
18506 * the Wide board. The total size is about 16 KB, so
18507 * allocate all at once. If the allocation fails decrement
18508 * and try again.
18509 */
18510 for (req_cnt = adv_dvc_varp->max_host_qng;
18511 req_cnt > 0; req_cnt--) {
18512
18513 reqp = (adv_req_t *)
18514 kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
18515
18516 ASC_DBG3(1,
18517 "advansys_board_found: reqp 0x%lx, req_cnt %d, bytes %lu\n",
18518 (ulong)reqp, req_cnt,
18519 (ulong)sizeof(adv_req_t) * req_cnt);
18520
18521 if (reqp != NULL) {
18522 break;
18523 }
18524 }
18525 if (reqp == NULL) {
18526 goto kmalloc_error;
18527 }
18528
18529 /*
18530 * Allocate up to ADV_TOT_SG_BLOCK request structures for
18531 * the Wide board. Each structure is about 136 bytes.
18532 */
18533 boardp->adv_sgblkp = NULL;
18534 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
18535
18536 sgp = (adv_sgblk_t *)
18537 kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC);
18538
18539 if (sgp == NULL) {
18540 break;
18541 }
18542
18543 sgp->next_sgblkp = boardp->adv_sgblkp;
18544 boardp->adv_sgblkp = sgp;
18545
18546 }
18547 ASC_DBG3(1,
18548 "advansys_board_found: sg_cnt %d * %u = %u bytes\n",
18549 sg_cnt, sizeof(adv_sgblk_t),
18550 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
18551
18552 /*
18553 * If no request structures or scatter-gather structures could
18554 * be allocated, then return an error. Otherwise continue with
18555 * initialization.
18556 */
18557 kmalloc_error:
18558 if (carrp == NULL) {
18559 ASC_PRINT1
18560 ("advansys_board_found: board %d error: failed to kmalloc() carrier buffer.\n",
18561 boardp->id);
18562 err_code = ADV_ERROR;
18563 } else if (reqp == NULL) {
18564 kfree(carrp);
18565 ASC_PRINT1
18566 ("advansys_board_found: board %d error: failed to kmalloc() adv_req_t buffer.\n",
18567 boardp->id);
18568 err_code = ADV_ERROR;
18569 } else if (boardp->adv_sgblkp == NULL) {
18570 kfree(carrp);
18571 kfree(reqp);
18572 ASC_PRINT1
18573 ("advansys_board_found: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n",
18574 boardp->id);
18575 err_code = ADV_ERROR;
18576 } else {
18577
18578 /* Save carrier buffer pointer. */
18579 boardp->orig_carrp = carrp;
18580
18581 /*
18582 * Save original pointer for kfree() in case the
18583 * driver is built as a module and can be unloaded.
18584 */
18585 boardp->orig_reqp = reqp;
18586
18587 adv_dvc_varp->carrier_buf = carrp;
18588
18589 /*
18590 * Point 'adv_reqp' to the request structures and
18591 * link them together.
18592 */
18593 req_cnt--;
18594 reqp[req_cnt].next_reqp = NULL;
18595 for (; req_cnt > 0; req_cnt--) {
18596 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
18597 }
18598 boardp->adv_reqp = &reqp[0];
18599
18600 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
18601 ASC_DBG(2,
18602 "advansys_board_found: AdvInitAsc3550Driver()\n");
18603 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
18604 } else if (adv_dvc_varp->chip_type ==
18605 ADV_CHIP_ASC38C0800) {
18606 ASC_DBG(2,
18607 "advansys_board_found: AdvInitAsc38C0800Driver()\n");
18608 warn_code =
18609 AdvInitAsc38C0800Driver(adv_dvc_varp);
18610 } else {
18611 ASC_DBG(2,
18612 "advansys_board_found: AdvInitAsc38C1600Driver()\n");
18613 warn_code =
18614 AdvInitAsc38C1600Driver(adv_dvc_varp);
18615 }
18616 err_code = adv_dvc_varp->err_code;
18617
18618 if (warn_code || err_code) {
18619 ASC_PRINT3
18620 ("advansys_board_found: board %d error: warn 0x%x, error 0x%x\n",
18621 boardp->id, warn_code, err_code);
18622 }
18623 }
18624 }
18625
18626 if (err_code != 0) {
18627 release_region(shost->io_port, boardp->asc_n_io_port);
18628 if (ASC_WIDE_BOARD(boardp)) {
18629 iounmap(boardp->ioremap_addr);
18630 kfree(boardp->orig_carrp);
18631 boardp->orig_carrp = NULL;
18632 if (boardp->orig_reqp) {
18633 kfree(boardp->orig_reqp);
18634 boardp->orig_reqp = boardp->adv_reqp = NULL;
18635 }
18636 while ((sgp = boardp->adv_sgblkp) != NULL) {
18637 boardp->adv_sgblkp = sgp->next_sgblkp;
18638 kfree(sgp);
18639 }
18640 }
18641 if (shost->dma_channel != NO_ISA_DMA) {
18642 free_dma(shost->dma_channel);
18643 }
18644#ifdef CONFIG_PROC_FS
18645 kfree(boardp->prtbuf);
18646#endif /* CONFIG_PROC_FS */
18647 free_irq(shost->irq, boardp);
18648 scsi_unregister(shost);
18649 asc_board_count--;
18650 return NULL;
18651 }
18652 ASC_DBG_PRT_SCSI_HOST(2, shost);
18653
18654 return shost;
18655}
18656
18657/*
18658 * advansys_detect()
18659 *
18660 * Detect function for AdvanSys adapters.
18661 *
18662 * Argument is a pointer to the host driver's scsi_hosts entry.
18663 *
18664 * Return number of adapters found.
18665 *
18666 * Note: Because this function is called during system initialization
18667 * it must not call SCSI mid-level functions including scsi_malloc()
18668 * and scsi_free().
18669 */
18670static int __init advansys_detect(struct scsi_host_template *tpnt)
18671{
18672 static int detect_called = ASC_FALSE;
18673 int iop;
18674 int bus;
18675 int ioport = 0;
18676 struct device *dev = NULL;
18677#ifdef CONFIG_PCI
18678 int pci_init_search = 0;
18679 struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
18680 int pci_card_cnt_max = 0;
18681 int pci_card_cnt = 0;
18682 struct pci_dev *pdev = NULL;
18683 int pci_device_id_cnt = 0;
18684 unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
18685 PCI_DEVICE_ID_ASP_1200A,
18686 PCI_DEVICE_ID_ASP_ABP940,
18687 PCI_DEVICE_ID_ASP_ABP940U,
18688 PCI_DEVICE_ID_ASP_ABP940UW,
18689 PCI_DEVICE_ID_38C0800_REV1,
18690 PCI_DEVICE_ID_38C1600_REV1
18691 };
18692#endif /* CONFIG_PCI */
18693
18694 if (detect_called == ASC_FALSE) {
18695 detect_called = ASC_TRUE;
18696 } else {
18697 printk
18698 ("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
18699 return 0;
18700 }
18701
18702 ASC_DBG(1, "advansys_detect: begin\n");
18703
18704 asc_board_count = 0;
18705
18706 /*
18707 * If I/O port probing has been modified, then verify and
18708 * clean-up the 'asc_ioport' list.
18709 */
18710 if (asc_iopflag == ASC_TRUE) {
18711 for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
18712 ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
18713 ioport, asc_ioport[ioport]);
18714 if (asc_ioport[ioport] != 0) {
18715 for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX;
18716 iop++) {
18717 if (_asc_def_iop_base[iop] ==
18718 asc_ioport[ioport]) {
18719 break;
18720 }
18721 }
18722 if (iop == ASC_IOADR_TABLE_MAX_IX) {
18723 printk
18724 ("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
18725 asc_ioport[ioport]);
18726 asc_ioport[ioport] = 0;
18727 }
18728 }
18729 }
18730 ioport = 0;
18731 }
18732
18733 for (bus = 0; bus < ASC_NUM_BUS; bus++) {
18734
18735 ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
18736 bus, asc_bus_name[bus]);
18737 iop = 0;
18738
18739 while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
18740
18741 ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
18742 asc_board_count);
18743
18744 switch (asc_bus[bus]) {
18745 case ASC_IS_ISA:
18746 case ASC_IS_VL:
18747#ifdef CONFIG_ISA
18748 if (asc_iopflag == ASC_FALSE) {
18749 iop =
18750 AscSearchIOPortAddr(iop,
18751 asc_bus[bus]);
18752 } else {
18753 /*
18754 * ISA and VL I/O port scanning has either been
18755 * eliminated or limited to selected ports on
18756 * the LILO command line, /etc/lilo.conf, or
18757 * by setting variables when the module was loaded.
18758 */
18759 ASC_DBG(1,
18760 "advansys_detect: I/O port scanning modified\n");
18761 ioport_try_again:
18762 iop = 0;
18763 for (; ioport < ASC_NUM_IOPORT_PROBE;
18764 ioport++) {
18765 if ((iop =
18766 asc_ioport[ioport]) != 0) {
18767 break;
18768 }
18769 }
18770 if (iop) {
18771 ASC_DBG1(1,
18772 "advansys_detect: probing I/O port 0x%x...\n",
18773 iop);
18774 if (!request_region
18775 (iop, ASC_IOADR_GAP,
18776 "advansys")) {
18777 printk
18778 ("AdvanSys SCSI: specified I/O Port 0x%X is busy\n",
18779 iop);
18780 /* Don't try this I/O port twice. */
18781 asc_ioport[ioport] = 0;
18782 goto ioport_try_again;
18783 } else if (AscFindSignature(iop)
18784 == ASC_FALSE) {
18785 printk
18786 ("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n",
18787 iop);
18788 /* Don't try this I/O port twice. */
18789 release_region(iop,
18790 ASC_IOADR_GAP);
18791 asc_ioport[ioport] = 0;
18792 goto ioport_try_again;
18793 } else {
18794 /*
18795 * If this isn't an ISA board, then it must be
18796 * a VL board. If currently looking an ISA
18797 * board is being looked for then try for
18798 * another ISA board in 'asc_ioport'.
18799 */
18800 if (asc_bus[bus] ==
18801 ASC_IS_ISA
18802 &&
18803 (AscGetChipVersion
18804 (iop,
18805 ASC_IS_ISA) &
18806 ASC_CHIP_VER_ISA_BIT)
18807 == 0) {
18808 /*
18809 * Don't clear 'asc_ioport[ioport]'. Try
18810 * this board again for VL. Increment
18811 * 'ioport' past this board.
18812 */
18813 ioport++;
18814 release_region
18815 (iop,
18816 ASC_IOADR_GAP);
18817 goto ioport_try_again;
18818 }
18819 }
18820 /*
18821 * This board appears good, don't try the I/O port
18822 * again by clearing its value. Increment 'ioport'
18823 * for the next iteration.
18824 */
18825 asc_ioport[ioport++] = 0;
18826 }
18827 }
18828#endif /* CONFIG_ISA */
18829 break;
18830
18831 case ASC_IS_EISA:
18832#ifdef CONFIG_ISA
18833 iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
18834#endif /* CONFIG_ISA */
18835 break;
18836
18837 case ASC_IS_PCI:
18838#ifdef CONFIG_PCI
18839 if (pci_init_search == 0) {
18840 int i, j;
18841
18842 pci_init_search = 1;
18843
18844 /* Find all PCI cards. */
18845 while (pci_device_id_cnt <
18846 ASC_PCI_DEVICE_ID_CNT) {
18847 if ((pdev =
18848 pci_find_device
18849 (PCI_VENDOR_ID_ASP,
18850 pci_device_id
18851 [pci_device_id_cnt],
18852 pdev)) == NULL) {
18853 pci_device_id_cnt++;
18854 } else {
18855 if (pci_enable_device
18856 (pdev) == 0) {
18857 pci_devicep
18858 [pci_card_cnt_max++]
18859 = pdev;
18860 }
18861 }
18862 }
18863
18864 /*
18865 * Sort PCI cards in ascending order by PCI Bus, Slot,
18866 * and Device Number.
18867 */
18868 for (i = 0; i < pci_card_cnt_max - 1;
18869 i++) {
18870 for (j = i + 1;
18871 j < pci_card_cnt_max;
18872 j++) {
18873 if ((pci_devicep[j]->
18874 bus->number <
18875 pci_devicep[i]->
18876 bus->number)
18877 ||
18878 ((pci_devicep[j]->
18879 bus->number ==
18880 pci_devicep[i]->
18881 bus->number)
18882 &&
18883 (pci_devicep[j]->
18884 devfn <
18885 pci_devicep[i]->
18886 devfn))) {
18887 pdev =
18888 pci_devicep
18889 [i];
18890 pci_devicep[i] =
18891 pci_devicep
18892 [j];
18893 pci_devicep[j] =
18894 pdev;
18895 }
18896 }
18897 }
18898
18899 pci_card_cnt = 0;
18900 } else {
18901 pci_card_cnt++;
18902 }
18903
18904 if (pci_card_cnt == pci_card_cnt_max) {
18905 iop = 0;
18906 } else {
18907 pdev = pci_devicep[pci_card_cnt];
18908
18909 ASC_DBG2(2,
18910 "advansys_detect: devfn %d, bus number %d\n",
18911 pdev->devfn,
18912 pdev->bus->number);
18913 iop = pci_resource_start(pdev, 0);
18914 ASC_DBG2(1,
18915 "advansys_detect: vendorID %X, deviceID %X\n",
18916 pdev->vendor,
18917 pdev->device);
18918 ASC_DBG2(2,
18919 "advansys_detect: iop %X, irqLine %d\n",
18920 iop, pdev->irq);
18921 }
18922 if (pdev)
18923 dev = &pdev->dev;
18924
18925#endif /* CONFIG_PCI */
18926 break;
18927
18928 default:
18929 ASC_PRINT1
18930 ("advansys_detect: unknown bus type: %d\n",
18931 asc_bus[bus]);
18932 break;
18933 }
18934 ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
18935
18936 /*
18937 * Adapter not found, try next bus type.
18938 */
18939 if (iop == 0) {
18940 break;
18941 }
18942
18943 advansys_board_found(iop, dev, asc_bus[bus]);
18944 }
18945 }
18946
18947 ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n",
18948 asc_board_count);
18949 return asc_board_count;
18950}
18951
18952/*
18953 * advansys_release()
18954 *
18955 * Release resources allocated for a single AdvanSys adapter.
18956 */
18957static int advansys_release(struct Scsi_Host *shost)
18958{
18959 asc_board_t *boardp;
18960
18961 ASC_DBG(1, "advansys_release: begin\n");
18962 boardp = ASC_BOARDP(shost);
18963 free_irq(shost->irq, boardp);
18964 if (shost->dma_channel != NO_ISA_DMA) {
18965 ASC_DBG(1, "advansys_release: free_dma()\n");
18966 free_dma(shost->dma_channel);
18967 }
18968 release_region(shost->io_port, boardp->asc_n_io_port);
18969 if (ASC_WIDE_BOARD(boardp)) {
18970 adv_sgblk_t *sgp = NULL;
18971
18972 iounmap(boardp->ioremap_addr);
18973 kfree(boardp->orig_carrp);
18974 boardp->orig_carrp = NULL;
18975 if (boardp->orig_reqp) {
18976 kfree(boardp->orig_reqp);
18977 boardp->orig_reqp = boardp->adv_reqp = NULL;
18978 }
18979 while ((sgp = boardp->adv_sgblkp) != NULL) {
18980 boardp->adv_sgblkp = sgp->next_sgblkp;
18981 kfree(sgp);
18982 }
18983 }
18984#ifdef CONFIG_PROC_FS
18985 ASC_ASSERT(boardp->prtbuf != NULL);
18986 kfree(boardp->prtbuf);
18987#endif /* CONFIG_PROC_FS */
18988 scsi_unregister(shost);
18989 ASC_DBG(1, "advansys_release: end\n");
18990 return 0;
18991}
18992
Randy Dunlapd8dafd82006-11-21 13:50:47 -080018993#ifdef CONFIG_PCI
Dave Jones2672ea82006-08-02 17:11:49 -040018994/* PCI Devices supported by this driver */
18995static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018996 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
18997 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18998 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
18999 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
19000 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
19001 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
19002 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
19003 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
19004 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
19005 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
19006 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
19007 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
19008 {}
Dave Jones2672ea82006-08-02 17:11:49 -040019009};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040019010
Dave Jones2672ea82006-08-02 17:11:49 -040019011MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Randy Dunlapd8dafd82006-11-21 13:50:47 -080019012#endif /* CONFIG_PCI */
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040019013
19014MODULE_LICENSE("GPL");