blob: 303dc98b45c0a974bc94a6be3f4bad528a5108c4 [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 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003828 /* /proc/scsi/advansys/[0...] */
3829 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003831 struct asc_stats asc_stats; /* Board statistics */
3832#endif /* ADVANSYS_STATS */
3833 /*
3834 * The following fields are used only for Narrow Boards.
3835 */
3836 /* The following three structures must be in DMA-able memory. */
3837 ASC_SCSI_REQ_Q scsireqq;
3838 ASC_CAP_INFO cap_info;
3839 ASC_SCSI_INQUIRY inquiry;
3840 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3841 /*
3842 * The following fields are used only for Wide Boards.
3843 */
3844 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3845 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06003846 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003847 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3848 adv_req_t *adv_reqp; /* Request structures. */
3849 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3850 ushort bios_signature; /* BIOS Signature. */
3851 ushort bios_version; /* BIOS Version. */
3852 ushort bios_codeseg; /* BIOS Code Segment. */
3853 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854} asc_board_t;
3855
3856/*
3857 * PCI configuration structures
3858 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003859typedef struct _PCI_DATA_ {
3860 uchar type;
3861 uchar bus;
3862 uchar slot;
3863 uchar func;
3864 uchar offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865} PCI_DATA;
3866
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003867typedef struct _PCI_DEVICE_ {
3868 ushort vendorID;
3869 ushort deviceID;
3870 ushort slotNumber;
3871 ushort slotFound;
3872 uchar busNumber;
3873 uchar maxBusNumber;
3874 uchar devFunc;
3875 ushort startSlot;
3876 ushort endSlot;
3877 uchar bridge;
3878 uchar type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879} PCI_DEVICE;
3880
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003881typedef struct _PCI_CONFIG_SPACE_ {
3882 ushort vendorID;
3883 ushort deviceID;
3884 ushort command;
3885 ushort status;
3886 uchar revision;
3887 uchar classCode[3];
3888 uchar cacheSize;
3889 uchar latencyTimer;
3890 uchar headerType;
3891 uchar bist;
3892 ADV_PADDR baseAddress[6];
3893 ushort reserved[4];
3894 ADV_PADDR optionRomAddr;
3895 ushort reserved2[4];
3896 uchar irqLine;
3897 uchar irqPin;
3898 uchar minGnt;
3899 uchar maxLatency;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900} PCI_CONFIG_SPACE;
3901
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902/*
3903 * --- Driver Data
3904 */
3905
3906/* Note: All driver global data should be initialized. */
3907
3908/* Number of boards detected in system. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003909static int asc_board_count = 0;
3910static struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911
3912/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003913static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914
3915/*
3916 * Global structures required to issue a command.
3917 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003918static ASC_SCSI_Q asc_scsi_q = { {0} };
3919static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920
3921/* List of supported bus types. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003922static ushort asc_bus[ASC_NUM_BUS] __initdata = {
3923 ASC_IS_ISA,
3924 ASC_IS_VL,
3925 ASC_IS_EISA,
3926 ASC_IS_PCI,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927};
3928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003929static int asc_iopflag = ASC_FALSE;
3930static int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931
3932#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003933static char *asc_bus_name[ASC_NUM_BUS] = {
3934 "ASC_IS_ISA",
3935 "ASC_IS_VL",
3936 "ASC_IS_EISA",
3937 "ASC_IS_PCI",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938};
3939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003940static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941#endif /* ADVANSYS_DEBUG */
3942
3943/* Declaration for Asc Library internal data referenced by driver. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003944static PortAddr _asc_def_iop_base[];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945
3946/*
3947 * --- Driver Function Prototypes
3948 *
3949 * advansys.h contains function prototypes for functions global to Linux.
3950 */
3951
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003952static int advansys_slave_configure(struct scsi_device *);
3953static void asc_scsi_done_list(struct scsi_cmnd *);
3954static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3955static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3956static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3957static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
3958static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
3959static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3960static void adv_async_callback(ADV_DVC_VAR *, uchar);
3961static void asc_enqueue(asc_queue_t *, REQP, int);
3962static REQP asc_dequeue(asc_queue_t *, int);
3963static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3964static int asc_rmqueue(asc_queue_t *, REQP);
3965static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003967static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3968static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3969static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3970static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3971static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3972static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3973static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3974static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3975static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3976static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977#endif /* CONFIG_PROC_FS */
3978
3979/* Declaration for Asc Library internal functions referenced by driver. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003980static int AscFindSignature(PortAddr);
3981static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982
3983/* Statistics function prototypes. */
3984#ifdef ADVANSYS_STATS
3985#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003986static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3987static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988#endif /* CONFIG_PROC_FS */
3989#endif /* ADVANSYS_STATS */
3990
3991/* Debug function prototypes. */
3992#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003993static void asc_prt_scsi_host(struct Scsi_Host *);
3994static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
3995static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
3996static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
3997static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
3998static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
3999static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
4000static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
4001static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
4002static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
4003static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004#endif /* ADVANSYS_DEBUG */
4005
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006#ifdef CONFIG_PROC_FS
4007/*
4008 * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
4009 *
4010 * *buffer: I/O buffer
4011 * **start: if inout == FALSE pointer into buffer where user read should start
4012 * offset: current offset into a /proc/scsi/advansys/[0...] file
4013 * length: length of buffer
4014 * hostno: Scsi_Host host_no
4015 * inout: TRUE - user is writing; FALSE - user is reading
4016 *
4017 * Return the number of bytes read from or written to a
4018 * /proc/scsi/advansys/[0...] file.
4019 *
4020 * Note: This function uses the per board buffer 'prtbuf' which is
4021 * allocated when the board is initialized in advansys_detect(). The
4022 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
4023 * used to write to the buffer. The way asc_proc_copy() is written
4024 * if 'prtbuf' is too small it will not be overwritten. Instead the
4025 * user just won't get all the available statistics.
4026 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004027static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004029 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004031 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004032 char *cp;
4033 int cplen;
4034 int cnt;
4035 int totcnt;
4036 int leftlen;
4037 char *curbuf;
4038 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004040 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041#endif /* ADVANSYS_STATS */
4042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004043 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004045 /*
4046 * User write not supported.
4047 */
4048 if (inout == TRUE) {
4049 return (-ENOSYS);
4050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004052 /*
4053 * User read of /proc/scsi/advansys/[0...] file.
4054 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055
Matthew Wilcox2a437952007-07-26 11:00:51 -04004056 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004058 /* Copy read data starting at the beginning of the buffer. */
4059 *start = buffer;
4060 curbuf = buffer;
4061 advoffset = 0;
4062 totcnt = 0;
4063 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004065 /*
4066 * Get board configuration information.
4067 *
4068 * advansys_info() returns the board string from its own static buffer.
4069 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04004070 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004071 strcat(cp, "\n");
4072 cplen = strlen(cp);
4073 /* Copy board information. */
4074 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4075 totcnt += cnt;
4076 leftlen -= cnt;
4077 if (leftlen == 0) {
4078 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4079 return totcnt;
4080 }
4081 advoffset += cplen;
4082 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004084 /*
4085 * Display Wide Board BIOS Information.
4086 */
4087 if (ASC_WIDE_BOARD(boardp)) {
4088 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004089 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004090 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4091 cnt =
4092 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
4093 cplen);
4094 totcnt += cnt;
4095 leftlen -= cnt;
4096 if (leftlen == 0) {
4097 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4098 return totcnt;
4099 }
4100 advoffset += cplen;
4101 curbuf += cnt;
4102 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004104 /*
4105 * Display driver information for each device attached to the board.
4106 */
4107 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004108 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004109 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4110 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4111 totcnt += cnt;
4112 leftlen -= cnt;
4113 if (leftlen == 0) {
4114 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4115 return totcnt;
4116 }
4117 advoffset += cplen;
4118 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004120 /*
4121 * Display EEPROM configuration for the board.
4122 */
4123 cp = boardp->prtbuf;
4124 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004125 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004126 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004127 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004128 }
4129 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4130 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4131 totcnt += cnt;
4132 leftlen -= cnt;
4133 if (leftlen == 0) {
4134 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4135 return totcnt;
4136 }
4137 advoffset += cplen;
4138 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004140 /*
4141 * Display driver configuration and information for the board.
4142 */
4143 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004144 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004145 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4146 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4147 totcnt += cnt;
4148 leftlen -= cnt;
4149 if (leftlen == 0) {
4150 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4151 return totcnt;
4152 }
4153 advoffset += cplen;
4154 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155
4156#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004157 /*
4158 * Display driver statistics for the board.
4159 */
4160 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004161 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004162 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4163 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4164 totcnt += cnt;
4165 leftlen -= cnt;
4166 if (leftlen == 0) {
4167 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4168 return totcnt;
4169 }
4170 advoffset += cplen;
4171 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004173 /*
4174 * Display driver statistics for each target.
4175 */
4176 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
4177 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004178 cplen = asc_prt_target_stats(shost, tgt_id, cp,
4179 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004180 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4181 cnt =
4182 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
4183 cplen);
4184 totcnt += cnt;
4185 leftlen -= cnt;
4186 if (leftlen == 0) {
4187 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4188 return totcnt;
4189 }
4190 advoffset += cplen;
4191 curbuf += cnt;
4192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193#endif /* ADVANSYS_STATS */
4194
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004195 /*
4196 * Display Asc Library dynamic configuration information
4197 * for the board.
4198 */
4199 cp = boardp->prtbuf;
4200 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004201 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004202 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004203 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004204 }
4205 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4206 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4207 totcnt += cnt;
4208 leftlen -= cnt;
4209 if (leftlen == 0) {
4210 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4211 return totcnt;
4212 }
4213 advoffset += cplen;
4214 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004216 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004218 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219}
4220#endif /* CONFIG_PROC_FS */
4221
4222/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 * advansys_info()
4224 *
4225 * Return suitable for printing on the console with the argument
4226 * adapter's configuration information.
4227 *
4228 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
4229 * otherwise the static 'info' array will be overrun.
4230 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004231static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004233 static char info[ASC_INFO_SIZE];
4234 asc_board_t *boardp;
4235 ASC_DVC_VAR *asc_dvc_varp;
4236 ADV_DVC_VAR *adv_dvc_varp;
4237 char *busname;
4238 int iolen;
4239 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004241 boardp = ASC_BOARDP(shost);
4242 if (ASC_NARROW_BOARD(boardp)) {
4243 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
4244 ASC_DBG(1, "advansys_info: begin\n");
4245 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
4246 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
4247 ASC_IS_ISAPNP) {
4248 busname = "ISA PnP";
4249 } else {
4250 busname = "ISA";
4251 }
4252 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4253 sprintf(info,
4254 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
4255 ASC_VERSION, busname,
4256 (ulong)shost->io_port,
4257 (ulong)shost->io_port + boardp->asc_n_io_port -
4258 1, shost->irq, shost->dma_channel);
4259 } else {
4260 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
4261 busname = "VL";
4262 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
4263 busname = "EISA";
4264 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
4265 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
4266 == ASC_IS_PCI_ULTRA) {
4267 busname = "PCI Ultra";
4268 } else {
4269 busname = "PCI";
4270 }
4271 } else {
4272 busname = "?";
4273 ASC_PRINT2
4274 ("advansys_info: board %d: unknown bus type %d\n",
4275 boardp->id, asc_dvc_varp->bus_type);
4276 }
4277 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4278 sprintf(info,
4279 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
4280 ASC_VERSION, busname,
4281 (ulong)shost->io_port,
4282 (ulong)shost->io_port + boardp->asc_n_io_port -
4283 1, shost->irq);
4284 }
4285 } else {
4286 /*
4287 * Wide Adapter Information
4288 *
4289 * Memory-mapped I/O is used instead of I/O space to access
4290 * the adapter, but display the I/O Port range. The Memory
4291 * I/O address is displayed through the driver /proc file.
4292 */
4293 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4294 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4295 iolen = ADV_3550_IOLEN;
4296 widename = "Ultra-Wide";
4297 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4298 iolen = ADV_38C0800_IOLEN;
4299 widename = "Ultra2-Wide";
4300 } else {
4301 iolen = ADV_38C1600_IOLEN;
4302 widename = "Ultra3-Wide";
4303 }
4304 sprintf(info,
4305 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
4306 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
4307 (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
4308 }
4309 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
4310 ASC_DBG(1, "advansys_info: end\n");
4311 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312}
4313
4314/*
4315 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
4316 *
4317 * This function always returns 0. Command return status is saved
4318 * in the 'scp' result field.
4319 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004320static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004321advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004323 struct Scsi_Host *shost;
4324 asc_board_t *boardp;
4325 ulong flags;
4326 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004328 shost = scp->device->host;
4329 boardp = ASC_BOARDP(shost);
4330 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004332 /* host_lock taken by mid-level prior to call but need to protect */
4333 /* against own ISR */
4334 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004336 /*
4337 * Block new commands while handling a reset or abort request.
4338 */
4339 if (boardp->flags & ASC_HOST_IN_RESET) {
4340 ASC_DBG1(1,
4341 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4342 (ulong)scp);
4343 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004345 /*
4346 * Add blocked requests to the board's 'done' queue. The queued
4347 * requests will be completed at the end of the abort or reset
4348 * handling.
4349 */
4350 asc_enqueue(&boardp->done, scp, ASC_BACK);
4351 spin_unlock_irqrestore(&boardp->lock, flags);
4352 return 0;
4353 }
4354
4355 /*
4356 * Attempt to execute any waiting commands for the board.
4357 */
4358 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4359 ASC_DBG(1,
4360 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4361 asc_execute_queue(&boardp->waiting);
4362 }
4363
4364 /*
4365 * Save the function pointer to Linux mid-level 'done' function
4366 * and attempt to execute the command.
4367 *
4368 * If ASC_NOERROR is returned the request has been added to the
4369 * board's 'active' queue and will be completed by the interrupt
4370 * handler.
4371 *
4372 * If ASC_BUSY is returned add the request to the board's per
4373 * target waiting list. This is the first time the request has
4374 * been tried. Add it to the back of the waiting list. It will be
4375 * retried later.
4376 *
4377 * If an error occurred, the request will have been placed on the
4378 * board's 'done' queue and must be completed before returning.
4379 */
4380 scp->scsi_done = done;
4381 switch (asc_execute_scsi_cmnd(scp)) {
4382 case ASC_NOERROR:
4383 break;
4384 case ASC_BUSY:
4385 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4386 break;
4387 case ASC_ERROR:
4388 default:
4389 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4390 /* Interrupts could be enabled here. */
4391 asc_scsi_done_list(done_scp);
4392 break;
4393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004396 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397}
4398
4399/*
4400 * advansys_reset()
4401 *
4402 * Reset the bus associated with the command 'scp'.
4403 *
4404 * This function runs its own thread. Interrupts must be blocked but
4405 * sleeping is allowed and no locking other than for host structures is
4406 * required. Returns SUCCESS or FAILED.
4407 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004408static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004410 struct Scsi_Host *shost;
4411 asc_board_t *boardp;
4412 ASC_DVC_VAR *asc_dvc_varp;
4413 ADV_DVC_VAR *adv_dvc_varp;
4414 ulong flags;
4415 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4416 struct scsi_cmnd *tscp, *new_last_scp;
4417 int status;
4418 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004420 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421
4422#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004423 if (scp->device->host != NULL) {
4424 ASC_STATS(scp->device->host, reset);
4425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426#endif /* ADVANSYS_STATS */
4427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004428 if ((shost = scp->device->host) == NULL) {
4429 scp->result = HOST_BYTE(DID_ERROR);
4430 return FAILED;
4431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004433 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004435 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4436 boardp->id);
4437 /*
4438 * Check for re-entrancy.
4439 */
4440 spin_lock_irqsave(&boardp->lock, flags);
4441 if (boardp->flags & ASC_HOST_IN_RESET) {
4442 spin_unlock_irqrestore(&boardp->lock, flags);
4443 return FAILED;
4444 }
4445 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004448 if (ASC_NARROW_BOARD(boardp)) {
4449 /*
4450 * Narrow Board
4451 */
4452 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004454 /*
4455 * Reset the chip and SCSI bus.
4456 */
4457 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4458 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004460 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4461 if (asc_dvc_varp->err_code) {
4462 ASC_PRINT2
4463 ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
4464 boardp->id, asc_dvc_varp->err_code);
4465 ret = FAILED;
4466 } else if (status) {
4467 ASC_PRINT2
4468 ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
4469 boardp->id, status);
4470 } else {
4471 ASC_PRINT1
4472 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4473 boardp->id);
4474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004476 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4477 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004479 } else {
4480 /*
4481 * Wide Board
4482 *
4483 * If the suggest reset bus flags are set, then reset the bus.
4484 * Otherwise only reset the device.
4485 */
4486 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004488 /*
4489 * Reset the target's SCSI bus.
4490 */
4491 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4492 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4493 case ASC_TRUE:
4494 ASC_PRINT1
4495 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4496 boardp->id);
4497 break;
4498 case ASC_FALSE:
4499 default:
4500 ASC_PRINT1
4501 ("advansys_reset: board %d: SCSI bus reset error.\n",
4502 boardp->id);
4503 ret = FAILED;
4504 break;
4505 }
4506 spin_lock_irqsave(&boardp->lock, flags);
4507 (void)AdvISR(adv_dvc_varp);
4508 }
4509 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004511 /*
4512 * Dequeue all board 'done' requests. A pointer to the last request
4513 * is returned in 'last_scp'.
4514 */
4515 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004517 /*
4518 * Dequeue all board 'active' requests for all devices and set
4519 * the request status to DID_RESET. A pointer to the last request
4520 * is returned in 'last_scp'.
4521 */
4522 if (done_scp == NULL) {
4523 done_scp =
4524 asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
4525 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4526 tscp->result = HOST_BYTE(DID_RESET);
4527 }
4528 } else {
4529 /* Append to 'done_scp' at the end with 'last_scp'. */
4530 ASC_ASSERT(last_scp != NULL);
4531 last_scp->host_scribble =
4532 (unsigned char *)asc_dequeue_list(&boardp->active,
4533 &new_last_scp,
4534 ASC_TID_ALL);
4535 if (new_last_scp != NULL) {
4536 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4537 for (tscp = REQPNEXT(last_scp); tscp;
4538 tscp = REQPNEXT(tscp)) {
4539 tscp->result = HOST_BYTE(DID_RESET);
4540 }
4541 last_scp = new_last_scp;
4542 }
4543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004545 /*
4546 * Dequeue all 'waiting' requests and set the request status
4547 * to DID_RESET.
4548 */
4549 if (done_scp == NULL) {
4550 done_scp =
4551 asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
4552 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4553 tscp->result = HOST_BYTE(DID_RESET);
4554 }
4555 } else {
4556 /* Append to 'done_scp' at the end with 'last_scp'. */
4557 ASC_ASSERT(last_scp != NULL);
4558 last_scp->host_scribble =
4559 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4560 &new_last_scp,
4561 ASC_TID_ALL);
4562 if (new_last_scp != NULL) {
4563 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4564 for (tscp = REQPNEXT(last_scp); tscp;
4565 tscp = REQPNEXT(tscp)) {
4566 tscp->result = HOST_BYTE(DID_RESET);
4567 }
4568 last_scp = new_last_scp;
4569 }
4570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004572 /* Save the time of the most recently completed reset. */
4573 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004575 /* Clear reset flag. */
4576 boardp->flags &= ~ASC_HOST_IN_RESET;
4577 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004579 /*
4580 * Complete all the 'done_scp' requests.
4581 */
4582 if (done_scp != NULL) {
4583 asc_scsi_done_list(done_scp);
4584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004586 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004588 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589}
4590
4591/*
4592 * advansys_biosparam()
4593 *
4594 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4595 * support is enabled for a drive.
4596 *
4597 * ip (information pointer) is an int array with the following definition:
4598 * ip[0]: heads
4599 * ip[1]: sectors
4600 * ip[2]: cylinders
4601 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004602static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004604 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004606 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004608 ASC_DBG(1, "advansys_biosparam: begin\n");
4609 ASC_STATS(sdev->host, biosparam);
4610 boardp = ASC_BOARDP(sdev->host);
4611 if (ASC_NARROW_BOARD(boardp)) {
4612 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4613 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4614 ip[0] = 255;
4615 ip[1] = 63;
4616 } else {
4617 ip[0] = 64;
4618 ip[1] = 32;
4619 }
4620 } else {
4621 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4622 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4623 ip[0] = 255;
4624 ip[1] = 63;
4625 } else {
4626 ip[0] = 64;
4627 ip[1] = 32;
4628 }
4629 }
4630 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4631 ASC_DBG(1, "advansys_biosparam: end\n");
4632 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633}
4634
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004635static int __init advansys_detect(struct scsi_host_template *tpnt);
4636static int advansys_release(struct Scsi_Host *shp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637
4638static struct scsi_host_template driver_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004639 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004641 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004643 .name = "advansys",
4644 .detect = advansys_detect,
4645 .release = advansys_release,
4646 .info = advansys_info,
4647 .queuecommand = advansys_queuecommand,
4648 .eh_bus_reset_handler = advansys_reset,
4649 .bios_param = advansys_biosparam,
4650 .slave_configure = advansys_slave_configure,
4651 /*
4652 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
4653 * must be set. The flag will be cleared in advansys_detect for non-ISA
4654 * adapters. Refer to the comment in scsi_module.c for more information.
4655 */
4656 .unchecked_isa_dma = 1,
4657 /*
4658 * All adapters controlled by this driver are capable of large
4659 * scatter-gather lists. According to the mid-level SCSI documentation
4660 * this obviates any performance gain provided by setting
4661 * 'use_clustering'. But empirically while CPU utilization is increased
4662 * by enabling clustering, I/O throughput increases as well.
4663 */
4664 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004667#include "scsi_module.c"
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668
4669/*
4670 * --- Miscellaneous Driver Functions
4671 */
4672
4673/*
4674 * First-level interrupt handler.
4675 *
4676 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4677 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4678 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4679 * to the AdvanSys driver which is for a device sharing an interrupt with
4680 * an AdvanSys adapter.
4681 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004682static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004684 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004685 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4686 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004687 struct Scsi_Host *shost = dev_id;
4688 asc_board_t *boardp = ASC_BOARDP(shost);
4689 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004691 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
4692 spin_lock_irqsave(&boardp->lock, flags);
4693 if (ASC_NARROW_BOARD(boardp)) {
4694 /*
4695 * Narrow Board
4696 */
4697 if (AscIsIntPending(shost->io_port)) {
4698 result = IRQ_HANDLED;
4699 ASC_STATS(shost, interrupt);
4700 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
4701 AscISR(&boardp->dvc_var.asc_dvc_var);
4702 }
4703 } else {
4704 /*
4705 * Wide Board
4706 */
4707 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4708 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4709 result = IRQ_HANDLED;
4710 ASC_STATS(shost, interrupt);
4711 }
4712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004714 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004715 * Start waiting requests and create a list of completed requests.
4716 *
4717 * If a reset request is being performed for the board, the reset
4718 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004719 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004720 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4721 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
4722 "last_scp 0x%p\n", done_scp, last_scp);
4723
4724 /* Start any waiting commands for the board. */
4725 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4726 ASC_DBG(1, "advansys_interrupt: before "
4727 "asc_execute_queue()\n");
4728 asc_execute_queue(&boardp->waiting);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004729 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004731 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004732 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004733 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004734 * 'done_scp' will always be NULL on the first iteration of
4735 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004736 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004737 if (done_scp == NULL) {
4738 done_scp = asc_dequeue_list(&boardp->done,
4739 &last_scp, ASC_TID_ALL);
4740 } else {
4741 ASC_ASSERT(last_scp != NULL);
4742 last_scp->host_scribble =
4743 (unsigned char *)asc_dequeue_list(&boardp->
4744 done,
4745 &new_last_scp,
4746 ASC_TID_ALL);
4747 if (new_last_scp != NULL) {
4748 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4749 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004750 }
4751 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004752 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004753 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004755 /*
4756 * If interrupts were enabled on entry, then they
4757 * are now enabled here.
4758 *
4759 * Complete all requests on the done list.
4760 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004762 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004764 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004765 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766}
4767
4768/*
4769 * Set the number of commands to queue per device for the
4770 * specified host adapter.
4771 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004772static int advansys_slave_configure(struct scsi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004774 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004776 boardp = ASC_BOARDP(device->host);
4777 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
4778 /*
4779 * Save a pointer to the device and set its initial/maximum
4780 * queue depth. Only save the pointer for a lun0 dev though.
4781 */
4782 if (device->lun == 0)
4783 boardp->device[device->id] = device;
4784 if (device->tagged_supported) {
4785 if (ASC_NARROW_BOARD(boardp)) {
4786 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4787 boardp->dvc_var.asc_dvc_var.
4788 max_dvc_qng[device->id]);
4789 } else {
4790 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4791 boardp->dvc_var.adv_dvc_var.
4792 max_dvc_qng);
4793 }
4794 } else {
4795 scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
4796 }
4797 ASC_DBG4(1,
4798 "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
4799 (ulong)device, (ulong)boardp, device->id, device->queue_depth);
4800 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801}
4802
4803/*
4804 * Complete all requests on the singly linked list pointed
4805 * to by 'scp'.
4806 *
4807 * Interrupts can be enabled on entry.
4808 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004809static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004811 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004813 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4814 while (scp != NULL) {
4815 asc_board_t *boardp;
4816 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004818 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4819 tscp = REQPNEXT(scp);
4820 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004822 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004824 if (ASC_NARROW_BOARD(boardp))
4825 dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
4826 else
4827 dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004829 if (scp->use_sg)
4830 dma_unmap_sg(dev,
4831 (struct scatterlist *)scp->request_buffer,
4832 scp->use_sg, scp->sc_data_direction);
4833 else if (scp->request_bufflen)
4834 dma_unmap_single(dev, scp->SCp.dma_handle,
4835 scp->request_bufflen,
4836 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004838 ASC_STATS(scp->device->host, done);
4839 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004841 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004843 scp = tscp;
4844 }
4845 ASC_DBG(2, "asc_scsi_done_list: done\n");
4846 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847}
4848
4849/*
4850 * Execute a single 'Scsi_Cmnd'.
4851 *
4852 * The function 'done' is called when the request has been completed.
4853 *
4854 * Scsi_Cmnd:
4855 *
4856 * host - board controlling device
4857 * device - device to send command
4858 * target - target of device
4859 * lun - lun of device
4860 * cmd_len - length of SCSI CDB
4861 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4862 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4863 *
4864 * if (use_sg == 0) {
4865 * request_buffer - buffer address for request
4866 * request_bufflen - length of request buffer
4867 * } else {
4868 * request_buffer - pointer to scatterlist structure
4869 * }
4870 *
4871 * sense_buffer - sense command buffer
4872 *
4873 * result (4 bytes of an int):
4874 * Byte Meaning
4875 * 0 SCSI Status Byte Code
4876 * 1 SCSI One Byte Message Code
4877 * 2 Host Error Code
4878 * 3 Mid-Level Error Code
4879 *
4880 * host driver fields:
4881 * SCp - Scsi_Pointer used for command processing status
4882 * scsi_done - used to save caller's done function
4883 * host_scribble - used for pointer to another struct scsi_cmnd
4884 *
4885 * If this function returns ASC_NOERROR the request has been enqueued
4886 * on the board's 'active' queue and will be completed from the
4887 * interrupt handler.
4888 *
4889 * If this function returns ASC_NOERROR the request has been enqueued
4890 * on the board's 'done' queue and must be completed by the caller.
4891 *
4892 * If ASC_BUSY is returned the request will be enqueued by the
4893 * caller on the target's waiting queue and re-tried later.
4894 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004895static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004897 asc_board_t *boardp;
4898 ASC_DVC_VAR *asc_dvc_varp;
4899 ADV_DVC_VAR *adv_dvc_varp;
4900 ADV_SCSI_REQ_Q *adv_scsiqp;
4901 struct scsi_device *device;
4902 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004904 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4905 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004907 boardp = ASC_BOARDP(scp->device->host);
4908 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004910 if (ASC_NARROW_BOARD(boardp)) {
4911 /*
4912 * Build and execute Narrow Board request.
4913 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004915 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004917 /*
4918 * Build Asc Library request structure using the
4919 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4920 *
4921 * If an error is returned, then the request has been
4922 * queued on the board done queue. It will be completed
4923 * by the caller.
4924 *
4925 * asc_build_req() can not return ASC_BUSY.
4926 */
4927 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4928 ASC_STATS(scp->device->host, build_error);
4929 return ASC_ERROR;
4930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004932 /*
4933 * Execute the command. If there is no error, add the command
4934 * to the active queue.
4935 */
4936 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4937 case ASC_NOERROR:
4938 ASC_STATS(scp->device->host, exe_noerror);
4939 /*
4940 * Increment monotonically increasing per device successful
4941 * request counter. Wrapping doesn't matter.
4942 */
4943 boardp->reqcnt[scp->device->id]++;
4944 asc_enqueue(&boardp->active, scp, ASC_BACK);
4945 ASC_DBG(1,
4946 "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
4947 break;
4948 case ASC_BUSY:
4949 /*
4950 * Caller will enqueue request on the target's waiting queue
4951 * and retry later.
4952 */
4953 ASC_STATS(scp->device->host, exe_busy);
4954 break;
4955 case ASC_ERROR:
4956 ASC_PRINT2
4957 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4958 boardp->id, asc_dvc_varp->err_code);
4959 ASC_STATS(scp->device->host, exe_error);
4960 scp->result = HOST_BYTE(DID_ERROR);
4961 asc_enqueue(&boardp->done, scp, ASC_BACK);
4962 break;
4963 default:
4964 ASC_PRINT2
4965 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
4966 boardp->id, asc_dvc_varp->err_code);
4967 ASC_STATS(scp->device->host, exe_unknown);
4968 scp->result = HOST_BYTE(DID_ERROR);
4969 asc_enqueue(&boardp->done, scp, ASC_BACK);
4970 break;
4971 }
4972 } else {
4973 /*
4974 * Build and execute Wide Board request.
4975 */
4976 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004978 /*
4979 * Build and get a pointer to an Adv Library request structure.
4980 *
4981 * If the request is successfully built then send it below,
4982 * otherwise return with an error.
4983 */
4984 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4985 case ASC_NOERROR:
4986 ASC_DBG(3,
4987 "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
4988 break;
4989 case ASC_BUSY:
4990 ASC_DBG(1,
4991 "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
4992 /*
4993 * If busy is returned the request has not been enqueued.
4994 * It will be enqueued by the caller on the target's waiting
4995 * queue and retried later.
4996 *
4997 * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
4998 * count wide board busy conditions. They are updated in
4999 * adv_build_req and adv_get_sglist, respectively.
5000 */
5001 return ASC_BUSY;
5002 case ASC_ERROR:
5003 /*
5004 * If an error is returned, then the request has been
5005 * queued on the board done queue. It will be completed
5006 * by the caller.
5007 */
5008 default:
5009 ASC_DBG(1,
5010 "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
5011 ASC_STATS(scp->device->host, build_error);
5012 return ASC_ERROR;
5013 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005015 /*
5016 * Execute the command. If there is no error, add the command
5017 * to the active queue.
5018 */
5019 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
5020 case ASC_NOERROR:
5021 ASC_STATS(scp->device->host, exe_noerror);
5022 /*
5023 * Increment monotonically increasing per device successful
5024 * request counter. Wrapping doesn't matter.
5025 */
5026 boardp->reqcnt[scp->device->id]++;
5027 asc_enqueue(&boardp->active, scp, ASC_BACK);
5028 ASC_DBG(1,
5029 "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
5030 break;
5031 case ASC_BUSY:
5032 /*
5033 * Caller will enqueue request on the target's waiting queue
5034 * and retry later.
5035 */
5036 ASC_STATS(scp->device->host, exe_busy);
5037 break;
5038 case ASC_ERROR:
5039 ASC_PRINT2
5040 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
5041 boardp->id, adv_dvc_varp->err_code);
5042 ASC_STATS(scp->device->host, exe_error);
5043 scp->result = HOST_BYTE(DID_ERROR);
5044 asc_enqueue(&boardp->done, scp, ASC_BACK);
5045 break;
5046 default:
5047 ASC_PRINT2
5048 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
5049 boardp->id, adv_dvc_varp->err_code);
5050 ASC_STATS(scp->device->host, exe_unknown);
5051 scp->result = HOST_BYTE(DID_ERROR);
5052 asc_enqueue(&boardp->done, scp, ASC_BACK);
5053 break;
5054 }
5055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005057 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
5058 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059}
5060
5061/*
5062 * Build a request structure for the Asc Library (Narrow Board).
5063 *
5064 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
5065 * used to build the request.
5066 *
5067 * If an error occurs, then queue the request on the board done
5068 * queue and return ASC_ERROR.
5069 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005070static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005072 struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005074 /*
5075 * Mutually exclusive access is required to 'asc_scsi_q' and
5076 * 'asc_sg_head' until after the request is started.
5077 */
5078 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005080 /*
5081 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
5082 */
5083 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005085 /*
5086 * Build the ASC_SCSI_Q request.
5087 *
5088 * For narrow boards a CDB length maximum of 12 bytes
5089 * is supported.
5090 */
5091 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
5092 ASC_PRINT3
5093 ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n",
5094 boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
5095 scp->result = HOST_BYTE(DID_ERROR);
5096 asc_enqueue(&boardp->done, scp, ASC_BACK);
5097 return ASC_ERROR;
5098 }
5099 asc_scsi_q.cdbptr = &scp->cmnd[0];
5100 asc_scsi_q.q2.cdb_len = scp->cmd_len;
5101 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
5102 asc_scsi_q.q1.target_lun = scp->device->lun;
5103 asc_scsi_q.q2.target_ix =
5104 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
5105 asc_scsi_q.q1.sense_addr =
5106 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5107 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005109 /*
5110 * If there are any outstanding requests for the current target,
5111 * then every 255th request send an ORDERED request. This heuristic
5112 * tries to retain the benefit of request sorting while preventing
5113 * request starvation. 255 is the max number of tags or pending commands
5114 * a device may have outstanding.
5115 *
5116 * The request count is incremented below for every successfully
5117 * started request.
5118 *
5119 */
5120 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
5121 (boardp->reqcnt[scp->device->id] % 255) == 0) {
5122 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
5123 } else {
5124 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
5125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005127 /*
5128 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
5129 * buffer command.
5130 */
5131 if (scp->use_sg == 0) {
5132 /*
5133 * CDB request of single contiguous buffer.
5134 */
5135 ASC_STATS(scp->device->host, cont_cnt);
5136 scp->SCp.dma_handle = scp->request_bufflen ?
5137 dma_map_single(dev, scp->request_buffer,
5138 scp->request_bufflen,
5139 scp->sc_data_direction) : 0;
5140 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
5141 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
5142 ASC_STATS_ADD(scp->device->host, cont_xfer,
5143 ASC_CEILING(scp->request_bufflen, 512));
5144 asc_scsi_q.q1.sg_queue_cnt = 0;
5145 asc_scsi_q.sg_head = NULL;
5146 } else {
5147 /*
5148 * CDB scatter-gather request list.
5149 */
5150 int sgcnt;
5151 int use_sg;
5152 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005154 slp = (struct scatterlist *)scp->request_buffer;
5155 use_sg =
5156 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005158 if (use_sg > scp->device->host->sg_tablesize) {
5159 ASC_PRINT3
5160 ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
5161 boardp->id, use_sg,
5162 scp->device->host->sg_tablesize);
5163 dma_unmap_sg(dev, slp, scp->use_sg,
5164 scp->sc_data_direction);
5165 scp->result = HOST_BYTE(DID_ERROR);
5166 asc_enqueue(&boardp->done, scp, ASC_BACK);
5167 return ASC_ERROR;
5168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005170 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005172 /*
5173 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
5174 * structure to point to it.
5175 */
5176 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005178 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5179 asc_scsi_q.sg_head = &asc_sg_head;
5180 asc_scsi_q.q1.data_cnt = 0;
5181 asc_scsi_q.q1.data_addr = 0;
5182 /* This is a byte value, otherwise it would need to be swapped. */
5183 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5184 ASC_STATS_ADD(scp->device->host, sg_elem,
5185 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005187 /*
5188 * Convert scatter-gather list into ASC_SG_HEAD list.
5189 */
5190 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5191 asc_sg_head.sg_list[sgcnt].addr =
5192 cpu_to_le32(sg_dma_address(slp));
5193 asc_sg_head.sg_list[sgcnt].bytes =
5194 cpu_to_le32(sg_dma_len(slp));
5195 ASC_STATS_ADD(scp->device->host, sg_xfer,
5196 ASC_CEILING(sg_dma_len(slp), 512));
5197 }
5198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005200 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5201 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005203 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204}
5205
5206/*
5207 * Build a request structure for the Adv Library (Wide Board).
5208 *
5209 * If an adv_req_t can not be allocated to issue the request,
5210 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5211 *
5212 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5213 * microcode for DMA addresses or math operations are byte swapped
5214 * to little-endian order.
5215 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005216static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005218 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005220 adv_req_t *reqp;
5221 ADV_SCSI_REQ_Q *scsiqp;
5222 int i;
5223 int ret;
5224 struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005226 /*
5227 * Allocate an adv_req_t structure from the board to execute
5228 * the command.
5229 */
5230 if (boardp->adv_reqp == NULL) {
5231 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5232 ASC_STATS(scp->device->host, adv_build_noreq);
5233 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005235 reqp = boardp->adv_reqp;
5236 boardp->adv_reqp = reqp->next_reqp;
5237 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005240 /*
5241 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5242 */
5243 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005245 /*
5246 * Initialize the structure.
5247 */
5248 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005250 /*
5251 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5252 */
5253 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005255 /*
5256 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5257 */
5258 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005260 /*
5261 * Build the ADV_SCSI_REQ_Q request.
5262 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005264 /*
5265 * Set CDB length and copy it to the request structure.
5266 * For wide boards a CDB length maximum of 16 bytes
5267 * is supported.
5268 */
5269 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5270 ASC_PRINT3
5271 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5272 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5273 scp->result = HOST_BYTE(DID_ERROR);
5274 asc_enqueue(&boardp->done, scp, ASC_BACK);
5275 return ASC_ERROR;
5276 }
5277 scsiqp->cdb_len = scp->cmd_len;
5278 /* Copy first 12 CDB bytes to cdb[]. */
5279 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5280 scsiqp->cdb[i] = scp->cmnd[i];
5281 }
5282 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5283 for (; i < scp->cmd_len; i++) {
5284 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005287 scsiqp->target_id = scp->device->id;
5288 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005290 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5291 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005293 /*
5294 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5295 * buffer command.
5296 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005298 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5299 scsiqp->vdata_addr = scp->request_buffer;
5300 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5301
5302 if (scp->use_sg == 0) {
5303 /*
5304 * CDB request of single contiguous buffer.
5305 */
5306 reqp->sgblkp = NULL;
5307 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5308 if (scp->request_bufflen) {
5309 scsiqp->vdata_addr = scp->request_buffer;
5310 scp->SCp.dma_handle =
5311 dma_map_single(dev, scp->request_buffer,
5312 scp->request_bufflen,
5313 scp->sc_data_direction);
5314 } else {
5315 scsiqp->vdata_addr = NULL;
5316 scp->SCp.dma_handle = 0;
5317 }
5318 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5319 scsiqp->sg_list_ptr = NULL;
5320 scsiqp->sg_real_addr = 0;
5321 ASC_STATS(scp->device->host, cont_cnt);
5322 ASC_STATS_ADD(scp->device->host, cont_xfer,
5323 ASC_CEILING(scp->request_bufflen, 512));
5324 } else {
5325 /*
5326 * CDB scatter-gather request list.
5327 */
5328 struct scatterlist *slp;
5329 int use_sg;
5330
5331 slp = (struct scatterlist *)scp->request_buffer;
5332 use_sg =
5333 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
5334
5335 if (use_sg > ADV_MAX_SG_LIST) {
5336 ASC_PRINT3
5337 ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
5338 boardp->id, use_sg,
5339 scp->device->host->sg_tablesize);
5340 dma_unmap_sg(dev, slp, scp->use_sg,
5341 scp->sc_data_direction);
5342 scp->result = HOST_BYTE(DID_ERROR);
5343 asc_enqueue(&boardp->done, scp, ASC_BACK);
5344
5345 /*
5346 * Free the 'adv_req_t' structure by adding it back to the
5347 * board free list.
5348 */
5349 reqp->next_reqp = boardp->adv_reqp;
5350 boardp->adv_reqp = reqp;
5351
5352 return ASC_ERROR;
5353 }
5354
5355 if ((ret =
5356 adv_get_sglist(boardp, reqp, scp,
5357 use_sg)) != ADV_SUCCESS) {
5358 /*
5359 * Free the adv_req_t structure by adding it back to the
5360 * board free list.
5361 */
5362 reqp->next_reqp = boardp->adv_reqp;
5363 boardp->adv_reqp = reqp;
5364
5365 return ret;
5366 }
5367
5368 ASC_STATS(scp->device->host, sg_cnt);
5369 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5370 }
5371
5372 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5373 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5374
5375 *adv_scsiqpp = scsiqp;
5376
5377 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378}
5379
5380/*
5381 * Build scatter-gather list for Adv Library (Wide Board).
5382 *
5383 * Additional ADV_SG_BLOCK structures will need to be allocated
5384 * if the total number of scatter-gather elements exceeds
5385 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5386 * assumed to be physically contiguous.
5387 *
5388 * Return:
5389 * ADV_SUCCESS(1) - SG List successfully created
5390 * ADV_ERROR(-1) - SG List creation failed
5391 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005392static int
5393adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5394 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005396 adv_sgblk_t *sgblkp;
5397 ADV_SCSI_REQ_Q *scsiqp;
5398 struct scatterlist *slp;
5399 int sg_elem_cnt;
5400 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5401 ADV_PADDR sg_block_paddr;
5402 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005404 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5405 slp = (struct scatterlist *)scp->request_buffer;
5406 sg_elem_cnt = use_sg;
5407 prev_sg_block = NULL;
5408 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005410 do {
5411 /*
5412 * Allocate a 'adv_sgblk_t' structure from the board free
5413 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5414 * (15) scatter-gather elements.
5415 */
5416 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5417 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5418 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005420 /*
5421 * Allocation failed. Free 'adv_sgblk_t' structures already
5422 * allocated for the request.
5423 */
5424 while ((sgblkp = reqp->sgblkp) != NULL) {
5425 /* Remove 'sgblkp' from the request list. */
5426 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005428 /* Add 'sgblkp' to the board free list. */
5429 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5430 boardp->adv_sgblkp = sgblkp;
5431 }
5432 return ASC_BUSY;
5433 } else {
5434 /* Complete 'adv_sgblk_t' board allocation. */
5435 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5436 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005438 /*
5439 * Get 8 byte aligned virtual and physical addresses for
5440 * the allocated ADV_SG_BLOCK structure.
5441 */
5442 sg_block =
5443 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5444 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005446 /*
5447 * Check if this is the first 'adv_sgblk_t' for the request.
5448 */
5449 if (reqp->sgblkp == NULL) {
5450 /* Request's first scatter-gather block. */
5451 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005453 /*
5454 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5455 * address pointers.
5456 */
5457 scsiqp->sg_list_ptr = sg_block;
5458 scsiqp->sg_real_addr =
5459 cpu_to_le32(sg_block_paddr);
5460 } else {
5461 /* Request's second or later scatter-gather block. */
5462 sgblkp->next_sgblkp = reqp->sgblkp;
5463 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005465 /*
5466 * Point the previous ADV_SG_BLOCK structure to
5467 * the newly allocated ADV_SG_BLOCK structure.
5468 */
5469 ASC_ASSERT(prev_sg_block != NULL);
5470 prev_sg_block->sg_ptr =
5471 cpu_to_le32(sg_block_paddr);
5472 }
5473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005475 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5476 sg_block->sg_list[i].sg_addr =
5477 cpu_to_le32(sg_dma_address(slp));
5478 sg_block->sg_list[i].sg_count =
5479 cpu_to_le32(sg_dma_len(slp));
5480 ASC_STATS_ADD(scp->device->host, sg_xfer,
5481 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005483 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5484 sg_block->sg_cnt = i + 1;
5485 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5486 return ADV_SUCCESS;
5487 }
5488 slp++;
5489 }
5490 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5491 prev_sg_block = sg_block;
5492 }
5493 while (1);
5494 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495}
5496
5497/*
5498 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5499 *
5500 * Interrupt callback function for the Narrow SCSI Asc Library.
5501 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005502static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005504 asc_board_t *boardp;
5505 struct scsi_cmnd *scp;
5506 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005508 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5509 (ulong)asc_dvc_varp, (ulong)qdonep);
5510 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005512 /*
5513 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5514 * command that has been completed.
5515 */
5516 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5517 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005519 if (scp == NULL) {
5520 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5521 return;
5522 }
5523 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005525 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005526 ASC_STATS(shost, callback);
5527 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005529 /*
5530 * If the request isn't found on the active queue, it may
5531 * have been removed to handle a reset request.
5532 * Display a message and return.
5533 */
5534 boardp = ASC_BOARDP(shost);
5535 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5536 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5537 ASC_PRINT2
5538 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5539 boardp->id, (ulong)scp);
5540 return;
5541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005543 /*
5544 * 'qdonep' contains the command's ending status.
5545 */
5546 switch (qdonep->d3.done_stat) {
5547 case QD_NO_ERROR:
5548 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5549 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005551 /*
5552 * If an INQUIRY command completed successfully, then call
5553 * the AscInquiryHandling() function to set-up the device.
5554 */
5555 if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
5556 (scp->request_bufflen - qdonep->remain_bytes) >= 8) {
5557 AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
5558 (ASC_SCSI_INQUIRY *)scp->
5559 request_buffer);
5560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005562 /*
5563 * Check for an underrun condition.
5564 *
5565 * If there was no error and an underrun condition, then
5566 * then return the number of underrun bytes.
5567 */
5568 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5569 qdonep->remain_bytes <= scp->request_bufflen) {
5570 ASC_DBG1(1,
5571 "asc_isr_callback: underrun condition %u bytes\n",
5572 (unsigned)qdonep->remain_bytes);
5573 scp->resid = qdonep->remain_bytes;
5574 }
5575 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005577 case QD_WITH_ERROR:
5578 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5579 switch (qdonep->d3.host_stat) {
5580 case QHSTA_NO_ERROR:
5581 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5582 ASC_DBG(2,
5583 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5584 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5585 sizeof(scp->sense_buffer));
5586 /*
5587 * Note: The 'status_byte()' macro used by target drivers
5588 * defined in scsi.h shifts the status byte returned by
5589 * host drivers right by 1 bit. This is why target drivers
5590 * also use right shifted status byte definitions. For
5591 * instance target drivers use CHECK_CONDITION, defined to
5592 * 0x1, instead of the SCSI defined check condition value
5593 * of 0x2. Host drivers are supposed to return the status
5594 * byte as it is defined by SCSI.
5595 */
5596 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5597 STATUS_BYTE(qdonep->d3.scsi_stat);
5598 } else {
5599 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5600 }
5601 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005603 default:
5604 /* QHSTA error occurred */
5605 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5606 qdonep->d3.host_stat);
5607 scp->result = HOST_BYTE(DID_BAD_TARGET);
5608 break;
5609 }
5610 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005612 case QD_ABORTED_BY_HOST:
5613 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5614 scp->result =
5615 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5616 scsi_msg) |
5617 STATUS_BYTE(qdonep->d3.scsi_stat);
5618 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005620 default:
5621 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5622 qdonep->d3.done_stat);
5623 scp->result =
5624 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5625 scsi_msg) |
5626 STATUS_BYTE(qdonep->d3.scsi_stat);
5627 break;
5628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005630 /*
5631 * If the 'init_tidmask' bit isn't already set for the target and the
5632 * current request finished normally, then set the bit for the target
5633 * to indicate that a device is present.
5634 */
5635 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5636 qdonep->d3.done_stat == QD_NO_ERROR &&
5637 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5638 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005641 /*
5642 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5643 * function, add the command to the end of the board's done queue.
5644 * The done function for the command will be called from
5645 * advansys_interrupt().
5646 */
5647 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005649 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650}
5651
5652/*
5653 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5654 *
5655 * Callback function for the Wide SCSI Adv Library.
5656 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005657static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005659 asc_board_t *boardp;
5660 adv_req_t *reqp;
5661 adv_sgblk_t *sgblkp;
5662 struct scsi_cmnd *scp;
5663 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005664 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005666 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5667 (ulong)adv_dvc_varp, (ulong)scsiqp);
5668 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005670 /*
5671 * Get the adv_req_t structure for the command that has been
5672 * completed. The adv_req_t structure actually contains the
5673 * completed ADV_SCSI_REQ_Q structure.
5674 */
5675 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5676 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5677 if (reqp == NULL) {
5678 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5679 return;
5680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005682 /*
5683 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5684 * command that has been completed.
5685 *
5686 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5687 * if any, are dropped, because a board structure pointer can not be
5688 * determined.
5689 */
5690 scp = reqp->cmndp;
5691 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5692 if (scp == NULL) {
5693 ASC_PRINT
5694 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5695 return;
5696 }
5697 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005699 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005700 ASC_STATS(shost, callback);
5701 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005703 /*
5704 * If the request isn't found on the active queue, it may have been
5705 * removed to handle a reset request. Display a message and return.
5706 *
5707 * Note: Because the structure may still be in use don't attempt
5708 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5709 */
5710 boardp = ASC_BOARDP(shost);
5711 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5712 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5713 ASC_PRINT2
5714 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5715 boardp->id, (ulong)scp);
5716 return;
5717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005719 /*
5720 * 'done_status' contains the command's ending status.
5721 */
5722 switch (scsiqp->done_status) {
5723 case QD_NO_ERROR:
5724 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5725 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005726
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005727 /*
5728 * Check for an underrun condition.
5729 *
5730 * If there was no error and an underrun condition, then
5731 * then return the number of underrun bytes.
5732 */
5733 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5734 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5735 resid_cnt <= scp->request_bufflen) {
5736 ASC_DBG1(1,
5737 "adv_isr_callback: underrun condition %lu bytes\n",
5738 (ulong)resid_cnt);
5739 scp->resid = resid_cnt;
5740 }
5741 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005743 case QD_WITH_ERROR:
5744 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5745 switch (scsiqp->host_status) {
5746 case QHSTA_NO_ERROR:
5747 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5748 ASC_DBG(2,
5749 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5750 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5751 sizeof(scp->sense_buffer));
5752 /*
5753 * Note: The 'status_byte()' macro used by target drivers
5754 * defined in scsi.h shifts the status byte returned by
5755 * host drivers right by 1 bit. This is why target drivers
5756 * also use right shifted status byte definitions. For
5757 * instance target drivers use CHECK_CONDITION, defined to
5758 * 0x1, instead of the SCSI defined check condition value
5759 * of 0x2. Host drivers are supposed to return the status
5760 * byte as it is defined by SCSI.
5761 */
5762 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5763 STATUS_BYTE(scsiqp->scsi_status);
5764 } else {
5765 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5766 }
5767 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005769 default:
5770 /* Some other QHSTA error occurred. */
5771 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5772 scsiqp->host_status);
5773 scp->result = HOST_BYTE(DID_BAD_TARGET);
5774 break;
5775 }
5776 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005778 case QD_ABORTED_BY_HOST:
5779 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5780 scp->result =
5781 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5782 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005784 default:
5785 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5786 scsiqp->done_status);
5787 scp->result =
5788 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5789 break;
5790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005792 /*
5793 * If the 'init_tidmask' bit isn't already set for the target and the
5794 * current request finished normally, then set the bit for the target
5795 * to indicate that a device is present.
5796 */
5797 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5798 scsiqp->done_status == QD_NO_ERROR &&
5799 scsiqp->host_status == QHSTA_NO_ERROR) {
5800 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5801 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005803 /*
5804 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5805 * function, add the command to the end of the board's done queue.
5806 * The done function for the command will be called from
5807 * advansys_interrupt().
5808 */
5809 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005811 /*
5812 * Free all 'adv_sgblk_t' structures allocated for the request.
5813 */
5814 while ((sgblkp = reqp->sgblkp) != NULL) {
5815 /* Remove 'sgblkp' from the request list. */
5816 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005818 /* Add 'sgblkp' to the board free list. */
5819 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5820 boardp->adv_sgblkp = sgblkp;
5821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005823 /*
5824 * Free the adv_req_t structure used with the command by adding
5825 * it back to the board free list.
5826 */
5827 reqp->next_reqp = boardp->adv_reqp;
5828 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005829
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005830 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005832 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005833}
5834
5835/*
5836 * adv_async_callback() - Adv Library asynchronous event callback function.
5837 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005838static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005840 switch (code) {
5841 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5842 /*
5843 * The firmware detected a SCSI Bus reset.
5844 */
5845 ASC_DBG(0,
5846 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5847 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005848
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005849 case ADV_ASYNC_RDMA_FAILURE:
5850 /*
5851 * Handle RDMA failure by resetting the SCSI Bus and
5852 * possibly the chip if it is unresponsive. Log the error
5853 * with a unique code.
5854 */
5855 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5856 AdvResetChipAndSB(adv_dvc_varp);
5857 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005859 case ADV_HOST_SCSI_BUS_RESET:
5860 /*
5861 * Host generated SCSI bus reset occurred.
5862 */
5863 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5864 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005866 default:
5867 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5868 break;
5869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870}
5871
5872/*
5873 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5874 * to indicate a command is queued for the device.
5875 *
5876 * 'flag' may be either ASC_FRONT or ASC_BACK.
5877 *
5878 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5879 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005880static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005882 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005884 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5885 (ulong)ascq, (ulong)reqp, flag);
5886 ASC_ASSERT(reqp != NULL);
5887 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5888 tid = REQPTID(reqp);
5889 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5890 if (flag == ASC_FRONT) {
5891 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5892 ascq->q_first[tid] = reqp;
5893 /* If the queue was empty, set the last pointer. */
5894 if (ascq->q_last[tid] == NULL) {
5895 ascq->q_last[tid] = reqp;
5896 }
5897 } else { /* ASC_BACK */
5898 if (ascq->q_last[tid] != NULL) {
5899 ascq->q_last[tid]->host_scribble =
5900 (unsigned char *)reqp;
5901 }
5902 ascq->q_last[tid] = reqp;
5903 reqp->host_scribble = NULL;
5904 /* If the queue was empty, set the first pointer. */
5905 if (ascq->q_first[tid] == NULL) {
5906 ascq->q_first[tid] = reqp;
5907 }
5908 }
5909 /* The queue has at least one entry, set its bit. */
5910 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005912 /* Maintain request queue statistics. */
5913 ascq->q_tot_cnt[tid]++;
5914 ascq->q_cur_cnt[tid]++;
5915 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5916 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5917 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5918 tid, ascq->q_max_cnt[tid]);
5919 }
5920 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005922 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5923 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924}
5925
5926/*
5927 * Return first queued 'REQP' on the specified queue for
5928 * the specified target device. Clear the 'tidmask' bit for
5929 * the device if no more commands are left queued for it.
5930 *
5931 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5932 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005933static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005935 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005937 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5938 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5939 if ((reqp = ascq->q_first[tid]) != NULL) {
5940 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5941 ascq->q_first[tid] = REQPNEXT(reqp);
5942 /* If the queue is empty, clear its bit and the last pointer. */
5943 if (ascq->q_first[tid] == NULL) {
5944 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5945 ASC_ASSERT(ascq->q_last[tid] == reqp);
5946 ascq->q_last[tid] = NULL;
5947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005949 /* Maintain request queue statistics. */
5950 ascq->q_cur_cnt[tid]--;
5951 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
5952 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005954 }
5955 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
5956 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957}
5958
5959/*
5960 * Return a pointer to a singly linked list of all the requests queued
5961 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
5962 *
5963 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
5964 * the last request returned in the singly linked list.
5965 *
5966 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
5967 * then all queued requests are concatenated into one list and
5968 * returned.
5969 *
5970 * Note: If 'lastpp' is used to append a new list to the end of
5971 * an old list, only change the old list last pointer if '*lastpp'
5972 * (or the function return value) is not NULL, i.e. use a temporary
5973 * variable for 'lastpp' and check its value after the function return
5974 * before assigning it to the list last pointer.
5975 *
5976 * Unfortunately collecting queuing time statistics adds overhead to
5977 * the function that isn't inherent to the function's algorithm.
5978 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005979static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005981 REQP firstp, lastp;
5982 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005984 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5985 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005987 /*
5988 * If 'tid' is not ASC_TID_ALL, return requests only for
5989 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
5990 * requests for all tids.
5991 */
5992 if (tid != ASC_TID_ALL) {
5993 /* Return all requests for the specified 'tid'. */
5994 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
5995 /* List is empty; Set first and last return pointers to NULL. */
5996 firstp = lastp = NULL;
5997 } else {
5998 firstp = ascq->q_first[tid];
5999 lastp = ascq->q_last[tid];
6000 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
6001 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006003 {
6004 REQP reqp;
6005 ascq->q_cur_cnt[tid] = 0;
6006 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
6007 REQTIMESTAT("asc_dequeue_list", ascq,
6008 reqp, tid);
6009 }
6010 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006012 }
6013 } else {
6014 /* Return all requests for all tids. */
6015 firstp = lastp = NULL;
6016 for (i = 0; i <= ADV_MAX_TID; i++) {
6017 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
6018 if (firstp == NULL) {
6019 firstp = ascq->q_first[i];
6020 lastp = ascq->q_last[i];
6021 } else {
6022 ASC_ASSERT(lastp != NULL);
6023 lastp->host_scribble =
6024 (unsigned char *)ascq->q_first[i];
6025 lastp = ascq->q_last[i];
6026 }
6027 ascq->q_first[i] = ascq->q_last[i] = NULL;
6028 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006029#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006030 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006032 }
6033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006035 {
6036 REQP reqp;
6037 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
6038 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
6039 reqp->device->id);
6040 }
6041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006043 }
6044 if (lastpp) {
6045 *lastpp = lastp;
6046 }
6047 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
6048 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049}
6050
6051/*
6052 * Remove the specified 'REQP' from the specified queue for
6053 * the specified target device. Clear the 'tidmask' bit for the
6054 * device if no more commands are left queued for it.
6055 *
6056 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
6057 *
6058 * Return ASC_TRUE if the command was found and removed,
6059 * otherwise return ASC_FALSE.
6060 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006061static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006062{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006063 REQP currp, prevp;
6064 int tid;
6065 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006067 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
6068 (ulong)ascq, (ulong)reqp);
6069 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006071 tid = REQPTID(reqp);
6072 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006073
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006074 /*
6075 * Handle the common case of 'reqp' being the first
6076 * entry on the queue.
6077 */
6078 if (reqp == ascq->q_first[tid]) {
6079 ret = ASC_TRUE;
6080 ascq->q_first[tid] = REQPNEXT(reqp);
6081 /* If the queue is now empty, clear its bit and the last pointer. */
6082 if (ascq->q_first[tid] == NULL) {
6083 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
6084 ASC_ASSERT(ascq->q_last[tid] == reqp);
6085 ascq->q_last[tid] = NULL;
6086 }
6087 } else if (ascq->q_first[tid] != NULL) {
6088 ASC_ASSERT(ascq->q_last[tid] != NULL);
6089 /*
6090 * Because the case of 'reqp' being the first entry has been
6091 * handled above and it is known the queue is not empty, if
6092 * 'reqp' is found on the queue it is guaranteed the queue will
6093 * not become empty and that 'q_first[tid]' will not be changed.
6094 *
6095 * Set 'prevp' to the first entry, 'currp' to the second entry,
6096 * and search for 'reqp'.
6097 */
6098 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
6099 currp; prevp = currp, currp = REQPNEXT(currp)) {
6100 if (currp == reqp) {
6101 ret = ASC_TRUE;
6102 prevp->host_scribble =
6103 (unsigned char *)REQPNEXT(currp);
6104 reqp->host_scribble = NULL;
6105 if (ascq->q_last[tid] == reqp) {
6106 ascq->q_last[tid] = prevp;
6107 }
6108 break;
6109 }
6110 }
6111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006113 /* Maintain request queue statistics. */
6114 if (ret == ASC_TRUE) {
6115 ascq->q_cur_cnt[tid]--;
6116 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
6117 }
6118 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006120 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
6121 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006122}
6123
6124/*
6125 * Execute as many queued requests as possible for the specified queue.
6126 *
6127 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
6128 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006129static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006131 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
6132 REQP reqp;
6133 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006134
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006135 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
6136 /*
6137 * Execute queued commands for devices attached to
6138 * the current board in round-robin fashion.
6139 */
6140 scan_tidmask = ascq->q_tidmask;
6141 do {
6142 for (i = 0; i <= ADV_MAX_TID; i++) {
6143 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
6144 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
6145 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6146 } else
6147 if (asc_execute_scsi_cmnd
6148 ((struct scsi_cmnd *)reqp)
6149 == ASC_BUSY) {
6150 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6151 /*
6152 * The request returned ASC_BUSY. Enqueue at the front of
6153 * target's waiting list to maintain correct ordering.
6154 */
6155 asc_enqueue(ascq, reqp, ASC_FRONT);
6156 }
6157 }
6158 }
6159 } while (scan_tidmask);
6160 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161}
6162
6163#ifdef CONFIG_PROC_FS
6164/*
6165 * asc_prt_board_devices()
6166 *
6167 * Print driver information for devices attached to the board.
6168 *
6169 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6170 * cf. asc_prt_line().
6171 *
6172 * Return the number of characters copied into 'cp'. No more than
6173 * 'cplen' characters will be copied to 'cp'.
6174 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006175static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006177 asc_board_t *boardp;
6178 int leftlen;
6179 int totlen;
6180 int len;
6181 int chip_scsi_id;
6182 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006184 boardp = ASC_BOARDP(shost);
6185 leftlen = cplen;
6186 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006187
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006188 len = asc_prt_line(cp, leftlen,
6189 "\nDevice Information for AdvanSys SCSI Host %d:\n",
6190 shost->host_no);
6191 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006193 if (ASC_NARROW_BOARD(boardp)) {
6194 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6195 } else {
6196 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6197 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006199 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6200 ASC_PRT_NEXT();
6201 for (i = 0; i <= ADV_MAX_TID; i++) {
6202 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6203 len = asc_prt_line(cp, leftlen, " %X,", i);
6204 ASC_PRT_NEXT();
6205 }
6206 }
6207 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6208 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006210 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211}
6212
6213/*
6214 * Display Wide Board BIOS Information.
6215 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006216static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006218 asc_board_t *boardp;
6219 int leftlen;
6220 int totlen;
6221 int len;
6222 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006224 boardp = ASC_BOARDP(shost);
6225 leftlen = cplen;
6226 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006228 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6229 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006231 /*
6232 * If the BIOS saved a valid signature, then fill in
6233 * the BIOS code segment base address.
6234 */
6235 if (boardp->bios_signature != 0x55AA) {
6236 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6237 ASC_PRT_NEXT();
6238 len = asc_prt_line(cp, leftlen,
6239 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6240 ASC_PRT_NEXT();
6241 len = asc_prt_line(cp, leftlen,
6242 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6243 ASC_PRT_NEXT();
6244 } else {
6245 major = (boardp->bios_version >> 12) & 0xF;
6246 minor = (boardp->bios_version >> 8) & 0xF;
6247 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006249 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6250 major, minor,
6251 letter >= 26 ? '?' : letter + 'A');
6252 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006254 /*
6255 * Current available ROM BIOS release is 3.1I for UW
6256 * and 3.2I for U2W. This code doesn't differentiate
6257 * UW and U2W boards.
6258 */
6259 if (major < 3 || (major <= 3 && minor < 1) ||
6260 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6261 len = asc_prt_line(cp, leftlen,
6262 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6263 ASC_PRT_NEXT();
6264 len = asc_prt_line(cp, leftlen,
6265 "ftp://ftp.connectcom.net/pub\n");
6266 ASC_PRT_NEXT();
6267 }
6268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006270 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271}
6272
6273/*
6274 * Add serial number to information bar if signature AAh
6275 * is found in at bit 15-9 (7 bits) of word 1.
6276 *
6277 * Serial Number consists fo 12 alpha-numeric digits.
6278 *
6279 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6280 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6281 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6282 * 5 - Product revision (A-J) Word0: " "
6283 *
6284 * Signature Word1: 15-9 (7 bits)
6285 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6286 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6287 *
6288 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6289 *
6290 * Note 1: Only production cards will have a serial number.
6291 *
6292 * Note 2: Signature is most significant 7 bits (0xFE).
6293 *
6294 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6295 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006296static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006297{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006298 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006299
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006300 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6301 return ASC_FALSE;
6302 } else {
6303 /*
6304 * First word - 6 digits.
6305 */
6306 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006308 /* Product type - 1st digit. */
6309 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6310 /* Product type is P=Prototype */
6311 *cp += 0x8;
6312 }
6313 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006315 /* Manufacturing location - 2nd digit. */
6316 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006318 /* Product ID - 3rd, 4th digits. */
6319 num = w & 0x3FF;
6320 *cp++ = '0' + (num / 100);
6321 num %= 100;
6322 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006324 /* Product revision - 5th digit. */
6325 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006327 /*
6328 * Second word
6329 */
6330 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006332 /*
6333 * Year - 6th digit.
6334 *
6335 * If bit 15 of third word is set, then the
6336 * last digit of the year is greater than 7.
6337 */
6338 if (serialnum[2] & 0x8000) {
6339 *cp++ = '8' + ((w & 0x1C0) >> 6);
6340 } else {
6341 *cp++ = '0' + ((w & 0x1C0) >> 6);
6342 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006343
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006344 /* Week of year - 7th, 8th digits. */
6345 num = w & 0x003F;
6346 *cp++ = '0' + num / 10;
6347 num %= 10;
6348 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006350 /*
6351 * Third word
6352 */
6353 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006355 /* Serial number - 9th digit. */
6356 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006358 /* 10th, 11th, 12th digits. */
6359 num = w % 1000;
6360 *cp++ = '0' + num / 100;
6361 num %= 100;
6362 *cp++ = '0' + num / 10;
6363 num %= 10;
6364 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006366 *cp = '\0'; /* Null Terminate the string. */
6367 return ASC_TRUE;
6368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369}
6370
6371/*
6372 * asc_prt_asc_board_eeprom()
6373 *
6374 * Print board EEPROM configuration.
6375 *
6376 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6377 * cf. asc_prt_line().
6378 *
6379 * Return the number of characters copied into 'cp'. No more than
6380 * 'cplen' characters will be copied to 'cp'.
6381 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006382static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006384 asc_board_t *boardp;
6385 ASC_DVC_VAR *asc_dvc_varp;
6386 int leftlen;
6387 int totlen;
6388 int len;
6389 ASCEEP_CONFIG *ep;
6390 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006392 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006393#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006394 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006395
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006396 boardp = ASC_BOARDP(shost);
6397 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6398 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006400 leftlen = cplen;
6401 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006403 len = asc_prt_line(cp, leftlen,
6404 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6405 shost->host_no);
6406 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006408 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6409 == ASC_TRUE) {
6410 len =
6411 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6412 serialstr);
6413 ASC_PRT_NEXT();
6414 } else {
6415 if (ep->adapter_info[5] == 0xBB) {
6416 len = asc_prt_line(cp, leftlen,
6417 " Default Settings Used for EEPROM-less Adapter.\n");
6418 ASC_PRT_NEXT();
6419 } else {
6420 len = asc_prt_line(cp, leftlen,
6421 " Serial Number Signature Not Present.\n");
6422 ASC_PRT_NEXT();
6423 }
6424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006425
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006426 len = asc_prt_line(cp, leftlen,
6427 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6428 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6429 ep->max_tag_qng);
6430 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006431
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006432 len = asc_prt_line(cp, leftlen,
6433 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6434 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006436 len = asc_prt_line(cp, leftlen, " Target ID: ");
6437 ASC_PRT_NEXT();
6438 for (i = 0; i <= ASC_MAX_TID; i++) {
6439 len = asc_prt_line(cp, leftlen, " %d", i);
6440 ASC_PRT_NEXT();
6441 }
6442 len = asc_prt_line(cp, leftlen, "\n");
6443 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006444
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006445 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6446 ASC_PRT_NEXT();
6447 for (i = 0; i <= ASC_MAX_TID; i++) {
6448 len = asc_prt_line(cp, leftlen, " %c",
6449 (ep->
6450 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6451 'N');
6452 ASC_PRT_NEXT();
6453 }
6454 len = asc_prt_line(cp, leftlen, "\n");
6455 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006457 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6458 ASC_PRT_NEXT();
6459 for (i = 0; i <= ASC_MAX_TID; i++) {
6460 len = asc_prt_line(cp, leftlen, " %c",
6461 (ep->
6462 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6463 'N');
6464 ASC_PRT_NEXT();
6465 }
6466 len = asc_prt_line(cp, leftlen, "\n");
6467 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006469 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6470 ASC_PRT_NEXT();
6471 for (i = 0; i <= ASC_MAX_TID; i++) {
6472 len = asc_prt_line(cp, leftlen, " %c",
6473 (ep->
6474 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6475 'N');
6476 ASC_PRT_NEXT();
6477 }
6478 len = asc_prt_line(cp, leftlen, "\n");
6479 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006480
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006481 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6482 ASC_PRT_NEXT();
6483 for (i = 0; i <= ASC_MAX_TID; i++) {
6484 len = asc_prt_line(cp, leftlen, " %c",
6485 (ep->
6486 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6487 'N');
6488 ASC_PRT_NEXT();
6489 }
6490 len = asc_prt_line(cp, leftlen, "\n");
6491 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006492
6493#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006494 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6495 len = asc_prt_line(cp, leftlen,
6496 " Host ISA DMA speed: %d MB/S\n",
6497 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6498 ASC_PRT_NEXT();
6499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006500#endif /* CONFIG_ISA */
6501
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006502 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006503}
6504
6505/*
6506 * asc_prt_adv_board_eeprom()
6507 *
6508 * Print board EEPROM configuration.
6509 *
6510 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6511 * cf. asc_prt_line().
6512 *
6513 * Return the number of characters copied into 'cp'. No more than
6514 * 'cplen' characters will be copied to 'cp'.
6515 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006516static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006517{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006518 asc_board_t *boardp;
6519 ADV_DVC_VAR *adv_dvc_varp;
6520 int leftlen;
6521 int totlen;
6522 int len;
6523 int i;
6524 char *termstr;
6525 uchar serialstr[13];
6526 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6527 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6528 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6529 ushort word;
6530 ushort *wordp;
6531 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006532
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006533 boardp = ASC_BOARDP(shost);
6534 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6535 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6536 ep_3550 = &boardp->eep_config.adv_3550_eep;
6537 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6538 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6539 } else {
6540 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006542
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006543 leftlen = cplen;
6544 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006545
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006546 len = asc_prt_line(cp, leftlen,
6547 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6548 shost->host_no);
6549 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006551 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6552 wordp = &ep_3550->serial_number_word1;
6553 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6554 wordp = &ep_38C0800->serial_number_word1;
6555 } else {
6556 wordp = &ep_38C1600->serial_number_word1;
6557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006558
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006559 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6560 len =
6561 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6562 serialstr);
6563 ASC_PRT_NEXT();
6564 } else {
6565 len = asc_prt_line(cp, leftlen,
6566 " Serial Number Signature Not Present.\n");
6567 ASC_PRT_NEXT();
6568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006569
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006570 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6571 len = asc_prt_line(cp, leftlen,
6572 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6573 ep_3550->adapter_scsi_id,
6574 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6575 ASC_PRT_NEXT();
6576 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6577 len = asc_prt_line(cp, leftlen,
6578 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6579 ep_38C0800->adapter_scsi_id,
6580 ep_38C0800->max_host_qng,
6581 ep_38C0800->max_dvc_qng);
6582 ASC_PRT_NEXT();
6583 } else {
6584 len = asc_prt_line(cp, leftlen,
6585 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6586 ep_38C1600->adapter_scsi_id,
6587 ep_38C1600->max_host_qng,
6588 ep_38C1600->max_dvc_qng);
6589 ASC_PRT_NEXT();
6590 }
6591 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6592 word = ep_3550->termination;
6593 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6594 word = ep_38C0800->termination_lvd;
6595 } else {
6596 word = ep_38C1600->termination_lvd;
6597 }
6598 switch (word) {
6599 case 1:
6600 termstr = "Low Off/High Off";
6601 break;
6602 case 2:
6603 termstr = "Low Off/High On";
6604 break;
6605 case 3:
6606 termstr = "Low On/High On";
6607 break;
6608 default:
6609 case 0:
6610 termstr = "Automatic";
6611 break;
6612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006613
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006614 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6615 len = asc_prt_line(cp, leftlen,
6616 " termination: %u (%s), bios_ctrl: 0x%x\n",
6617 ep_3550->termination, termstr,
6618 ep_3550->bios_ctrl);
6619 ASC_PRT_NEXT();
6620 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6621 len = asc_prt_line(cp, leftlen,
6622 " termination: %u (%s), bios_ctrl: 0x%x\n",
6623 ep_38C0800->termination_lvd, termstr,
6624 ep_38C0800->bios_ctrl);
6625 ASC_PRT_NEXT();
6626 } else {
6627 len = asc_prt_line(cp, leftlen,
6628 " termination: %u (%s), bios_ctrl: 0x%x\n",
6629 ep_38C1600->termination_lvd, termstr,
6630 ep_38C1600->bios_ctrl);
6631 ASC_PRT_NEXT();
6632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006633
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006634 len = asc_prt_line(cp, leftlen, " Target ID: ");
6635 ASC_PRT_NEXT();
6636 for (i = 0; i <= ADV_MAX_TID; i++) {
6637 len = asc_prt_line(cp, leftlen, " %X", i);
6638 ASC_PRT_NEXT();
6639 }
6640 len = asc_prt_line(cp, leftlen, "\n");
6641 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006643 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6644 word = ep_3550->disc_enable;
6645 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6646 word = ep_38C0800->disc_enable;
6647 } else {
6648 word = ep_38C1600->disc_enable;
6649 }
6650 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6651 ASC_PRT_NEXT();
6652 for (i = 0; i <= ADV_MAX_TID; i++) {
6653 len = asc_prt_line(cp, leftlen, " %c",
6654 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6655 ASC_PRT_NEXT();
6656 }
6657 len = asc_prt_line(cp, leftlen, "\n");
6658 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006659
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006660 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6661 word = ep_3550->tagqng_able;
6662 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6663 word = ep_38C0800->tagqng_able;
6664 } else {
6665 word = ep_38C1600->tagqng_able;
6666 }
6667 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6668 ASC_PRT_NEXT();
6669 for (i = 0; i <= ADV_MAX_TID; i++) {
6670 len = asc_prt_line(cp, leftlen, " %c",
6671 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6672 ASC_PRT_NEXT();
6673 }
6674 len = asc_prt_line(cp, leftlen, "\n");
6675 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006676
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006677 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6678 word = ep_3550->start_motor;
6679 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6680 word = ep_38C0800->start_motor;
6681 } else {
6682 word = ep_38C1600->start_motor;
6683 }
6684 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6685 ASC_PRT_NEXT();
6686 for (i = 0; i <= ADV_MAX_TID; i++) {
6687 len = asc_prt_line(cp, leftlen, " %c",
6688 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6689 ASC_PRT_NEXT();
6690 }
6691 len = asc_prt_line(cp, leftlen, "\n");
6692 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006693
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006694 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6695 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6696 ASC_PRT_NEXT();
6697 for (i = 0; i <= ADV_MAX_TID; i++) {
6698 len = asc_prt_line(cp, leftlen, " %c",
6699 (ep_3550->
6700 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6701 'Y' : 'N');
6702 ASC_PRT_NEXT();
6703 }
6704 len = asc_prt_line(cp, leftlen, "\n");
6705 ASC_PRT_NEXT();
6706 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006708 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6709 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6710 ASC_PRT_NEXT();
6711 for (i = 0; i <= ADV_MAX_TID; i++) {
6712 len = asc_prt_line(cp, leftlen, " %c",
6713 (ep_3550->
6714 ultra_able & ADV_TID_TO_TIDMASK(i))
6715 ? 'Y' : 'N');
6716 ASC_PRT_NEXT();
6717 }
6718 len = asc_prt_line(cp, leftlen, "\n");
6719 ASC_PRT_NEXT();
6720 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006721
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006722 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6723 word = ep_3550->wdtr_able;
6724 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6725 word = ep_38C0800->wdtr_able;
6726 } else {
6727 word = ep_38C1600->wdtr_able;
6728 }
6729 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6730 ASC_PRT_NEXT();
6731 for (i = 0; i <= ADV_MAX_TID; i++) {
6732 len = asc_prt_line(cp, leftlen, " %c",
6733 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6734 ASC_PRT_NEXT();
6735 }
6736 len = asc_prt_line(cp, leftlen, "\n");
6737 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006738
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006739 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6740 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6741 len = asc_prt_line(cp, leftlen,
6742 " Synchronous Transfer Speed (Mhz):\n ");
6743 ASC_PRT_NEXT();
6744 for (i = 0; i <= ADV_MAX_TID; i++) {
6745 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006746
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006747 if (i == 0) {
6748 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6749 } else if (i == 4) {
6750 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6751 } else if (i == 8) {
6752 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6753 } else if (i == 12) {
6754 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6755 }
6756 switch (sdtr_speed & ADV_MAX_TID) {
6757 case 0:
6758 speed_str = "Off";
6759 break;
6760 case 1:
6761 speed_str = " 5";
6762 break;
6763 case 2:
6764 speed_str = " 10";
6765 break;
6766 case 3:
6767 speed_str = " 20";
6768 break;
6769 case 4:
6770 speed_str = " 40";
6771 break;
6772 case 5:
6773 speed_str = " 80";
6774 break;
6775 default:
6776 speed_str = "Unk";
6777 break;
6778 }
6779 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6780 ASC_PRT_NEXT();
6781 if (i == 7) {
6782 len = asc_prt_line(cp, leftlen, "\n ");
6783 ASC_PRT_NEXT();
6784 }
6785 sdtr_speed >>= 4;
6786 }
6787 len = asc_prt_line(cp, leftlen, "\n");
6788 ASC_PRT_NEXT();
6789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006790
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006791 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006792}
6793
6794/*
6795 * asc_prt_driver_conf()
6796 *
6797 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6798 * cf. asc_prt_line().
6799 *
6800 * Return the number of characters copied into 'cp'. No more than
6801 * 'cplen' characters will be copied to 'cp'.
6802 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006803static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006804{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006805 asc_board_t *boardp;
6806 int leftlen;
6807 int totlen;
6808 int len;
6809 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006810
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006811 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006812
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006813 leftlen = cplen;
6814 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006815
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006816 len = asc_prt_line(cp, leftlen,
6817 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6818 shost->host_no);
6819 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006820
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006821 len = asc_prt_line(cp, leftlen,
6822 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6823 shost->host_busy, shost->last_reset, shost->max_id,
6824 shost->max_lun, shost->max_channel);
6825 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006826
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006827 len = asc_prt_line(cp, leftlen,
6828 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6829 shost->unique_id, shost->can_queue, shost->this_id,
6830 shost->sg_tablesize, shost->cmd_per_lun);
6831 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006832
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006833 len = asc_prt_line(cp, leftlen,
6834 " unchecked_isa_dma %d, use_clustering %d\n",
6835 shost->unchecked_isa_dma, shost->use_clustering);
6836 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006837
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006838 len = asc_prt_line(cp, leftlen,
6839 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6840 boardp->flags, boardp->last_reset, jiffies,
6841 boardp->asc_n_io_port);
6842 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006843
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006844 /* 'shost->n_io_port' may be truncated because it is only one byte. */
6845 len = asc_prt_line(cp, leftlen,
6846 " io_port 0x%x, n_io_port 0x%x\n",
6847 shost->io_port, shost->n_io_port);
6848 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006850 if (ASC_NARROW_BOARD(boardp)) {
6851 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6852 } else {
6853 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006855
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006856 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006857}
6858
6859/*
6860 * asc_prt_asc_board_info()
6861 *
6862 * Print dynamic board configuration information.
6863 *
6864 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6865 * cf. asc_prt_line().
6866 *
6867 * Return the number of characters copied into 'cp'. No more than
6868 * 'cplen' characters will be copied to 'cp'.
6869 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006870static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006871{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006872 asc_board_t *boardp;
6873 int chip_scsi_id;
6874 int leftlen;
6875 int totlen;
6876 int len;
6877 ASC_DVC_VAR *v;
6878 ASC_DVC_CFG *c;
6879 int i;
6880 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006881
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006882 boardp = ASC_BOARDP(shost);
6883 v = &boardp->dvc_var.asc_dvc_var;
6884 c = &boardp->dvc_cfg.asc_dvc_cfg;
6885 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006887 leftlen = cplen;
6888 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006889
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006890 len = asc_prt_line(cp, leftlen,
6891 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6892 shost->host_no);
6893 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006894
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006895 len = asc_prt_line(cp, leftlen,
6896 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6897 c->chip_version, c->lib_version, c->lib_serial_no,
6898 c->mcode_date);
6899 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006900
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006901 len = asc_prt_line(cp, leftlen,
6902 " mcode_version 0x%x, err_code %u\n",
6903 c->mcode_version, v->err_code);
6904 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006905
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006906 /* Current number of commands waiting for the host. */
6907 len = asc_prt_line(cp, leftlen,
6908 " Total Command Pending: %d\n", v->cur_total_qng);
6909 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006910
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006911 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6912 ASC_PRT_NEXT();
6913 for (i = 0; i <= ASC_MAX_TID; i++) {
6914 if ((chip_scsi_id == i) ||
6915 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6916 continue;
6917 }
6918 len = asc_prt_line(cp, leftlen, " %X:%c",
6919 i,
6920 (v->
6921 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6922 'Y' : 'N');
6923 ASC_PRT_NEXT();
6924 }
6925 len = asc_prt_line(cp, leftlen, "\n");
6926 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006927
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006928 /* Current number of commands waiting for a device. */
6929 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6930 ASC_PRT_NEXT();
6931 for (i = 0; i <= ASC_MAX_TID; i++) {
6932 if ((chip_scsi_id == i) ||
6933 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6934 continue;
6935 }
6936 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6937 ASC_PRT_NEXT();
6938 }
6939 len = asc_prt_line(cp, leftlen, "\n");
6940 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006941
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006942 /* Current limit on number of commands that can be sent to a device. */
6943 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6944 ASC_PRT_NEXT();
6945 for (i = 0; i <= ASC_MAX_TID; i++) {
6946 if ((chip_scsi_id == i) ||
6947 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6948 continue;
6949 }
6950 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
6951 ASC_PRT_NEXT();
6952 }
6953 len = asc_prt_line(cp, leftlen, "\n");
6954 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006955
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006956 /* Indicate whether the device has returned queue full status. */
6957 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
6958 ASC_PRT_NEXT();
6959 for (i = 0; i <= ASC_MAX_TID; i++) {
6960 if ((chip_scsi_id == i) ||
6961 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6962 continue;
6963 }
6964 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
6965 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
6966 i, boardp->queue_full_cnt[i]);
6967 } else {
6968 len = asc_prt_line(cp, leftlen, " %X:N", i);
6969 }
6970 ASC_PRT_NEXT();
6971 }
6972 len = asc_prt_line(cp, leftlen, "\n");
6973 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006974
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006975 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6976 ASC_PRT_NEXT();
6977 for (i = 0; i <= ASC_MAX_TID; i++) {
6978 if ((chip_scsi_id == i) ||
6979 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6980 continue;
6981 }
6982 len = asc_prt_line(cp, leftlen, " %X:%c",
6983 i,
6984 (v->
6985 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6986 'N');
6987 ASC_PRT_NEXT();
6988 }
6989 len = asc_prt_line(cp, leftlen, "\n");
6990 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006991
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006992 for (i = 0; i <= ASC_MAX_TID; i++) {
6993 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006994
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006995 if ((chip_scsi_id == i) ||
6996 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6997 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
6998 continue;
6999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007000
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007001 len = asc_prt_line(cp, leftlen, " %X:", i);
7002 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007004 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
7005 len = asc_prt_line(cp, leftlen, " Asynchronous");
7006 ASC_PRT_NEXT();
7007 } else {
7008 syn_period_ix =
7009 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
7010 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007011
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007012 len = asc_prt_line(cp, leftlen,
7013 " Transfer Period Factor: %d (%d.%d Mhz),",
7014 v->sdtr_period_tbl[syn_period_ix],
7015 250 /
7016 v->sdtr_period_tbl[syn_period_ix],
7017 ASC_TENTHS(250,
7018 v->
7019 sdtr_period_tbl
7020 [syn_period_ix]));
7021 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007022
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007023 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7024 boardp->
7025 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
7026 ASC_PRT_NEXT();
7027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007029 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7030 len = asc_prt_line(cp, leftlen, "*\n");
7031 renegotiate = 1;
7032 } else {
7033 len = asc_prt_line(cp, leftlen, "\n");
7034 }
7035 ASC_PRT_NEXT();
7036 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007037
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007038 if (renegotiate) {
7039 len = asc_prt_line(cp, leftlen,
7040 " * = Re-negotiation pending before next command.\n");
7041 ASC_PRT_NEXT();
7042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007043
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007044 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007045}
7046
7047/*
7048 * asc_prt_adv_board_info()
7049 *
7050 * Print dynamic board configuration information.
7051 *
7052 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7053 * cf. asc_prt_line().
7054 *
7055 * Return the number of characters copied into 'cp'. No more than
7056 * 'cplen' characters will be copied to 'cp'.
7057 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007058static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007059{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007060 asc_board_t *boardp;
7061 int leftlen;
7062 int totlen;
7063 int len;
7064 int i;
7065 ADV_DVC_VAR *v;
7066 ADV_DVC_CFG *c;
7067 AdvPortAddr iop_base;
7068 ushort chip_scsi_id;
7069 ushort lramword;
7070 uchar lrambyte;
7071 ushort tagqng_able;
7072 ushort sdtr_able, wdtr_able;
7073 ushort wdtr_done, sdtr_done;
7074 ushort period = 0;
7075 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007076
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007077 boardp = ASC_BOARDP(shost);
7078 v = &boardp->dvc_var.adv_dvc_var;
7079 c = &boardp->dvc_cfg.adv_dvc_cfg;
7080 iop_base = v->iop_base;
7081 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007083 leftlen = cplen;
7084 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007086 len = asc_prt_line(cp, leftlen,
7087 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
7088 shost->host_no);
7089 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007090
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007091 len = asc_prt_line(cp, leftlen,
7092 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
7093 v->iop_base,
7094 AdvReadWordRegister(iop_base,
7095 IOPW_SCSI_CFG1) & CABLE_DETECT,
7096 v->err_code);
7097 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007098
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007099 len = asc_prt_line(cp, leftlen,
7100 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
7101 c->chip_version, c->lib_version, c->mcode_date,
7102 c->mcode_version);
7103 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007105 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
7106 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
7107 ASC_PRT_NEXT();
7108 for (i = 0; i <= ADV_MAX_TID; i++) {
7109 if ((chip_scsi_id == i) ||
7110 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7111 continue;
7112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007113
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007114 len = asc_prt_line(cp, leftlen, " %X:%c",
7115 i,
7116 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7117 'N');
7118 ASC_PRT_NEXT();
7119 }
7120 len = asc_prt_line(cp, leftlen, "\n");
7121 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007122
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007123 len = asc_prt_line(cp, leftlen, " Queue Limit:");
7124 ASC_PRT_NEXT();
7125 for (i = 0; i <= ADV_MAX_TID; i++) {
7126 if ((chip_scsi_id == i) ||
7127 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7128 continue;
7129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007131 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
7132 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007133
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007134 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
7135 ASC_PRT_NEXT();
7136 }
7137 len = asc_prt_line(cp, leftlen, "\n");
7138 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007139
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007140 len = asc_prt_line(cp, leftlen, " Command Pending:");
7141 ASC_PRT_NEXT();
7142 for (i = 0; i <= ADV_MAX_TID; i++) {
7143 if ((chip_scsi_id == i) ||
7144 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7145 continue;
7146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007147
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007148 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
7149 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007150
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007151 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
7152 ASC_PRT_NEXT();
7153 }
7154 len = asc_prt_line(cp, leftlen, "\n");
7155 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007157 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
7158 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
7159 ASC_PRT_NEXT();
7160 for (i = 0; i <= ADV_MAX_TID; i++) {
7161 if ((chip_scsi_id == i) ||
7162 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7163 continue;
7164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007165
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007166 len = asc_prt_line(cp, leftlen, " %X:%c",
7167 i,
7168 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7169 'N');
7170 ASC_PRT_NEXT();
7171 }
7172 len = asc_prt_line(cp, leftlen, "\n");
7173 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007174
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007175 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
7176 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
7177 ASC_PRT_NEXT();
7178 for (i = 0; i <= ADV_MAX_TID; i++) {
7179 if ((chip_scsi_id == i) ||
7180 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7181 continue;
7182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007183
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007184 AdvReadWordLram(iop_base,
7185 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7186 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007187
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007188 len = asc_prt_line(cp, leftlen, " %X:%d",
7189 i, (lramword & 0x8000) ? 16 : 8);
7190 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007192 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
7193 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7194 len = asc_prt_line(cp, leftlen, "*");
7195 ASC_PRT_NEXT();
7196 renegotiate = 1;
7197 }
7198 }
7199 len = asc_prt_line(cp, leftlen, "\n");
7200 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007201
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007202 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7203 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7204 ASC_PRT_NEXT();
7205 for (i = 0; i <= ADV_MAX_TID; i++) {
7206 if ((chip_scsi_id == i) ||
7207 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7208 continue;
7209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007210
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007211 len = asc_prt_line(cp, leftlen, " %X:%c",
7212 i,
7213 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7214 'N');
7215 ASC_PRT_NEXT();
7216 }
7217 len = asc_prt_line(cp, leftlen, "\n");
7218 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007220 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7221 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007222
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007223 AdvReadWordLram(iop_base,
7224 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7225 lramword);
7226 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007227
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007228 if ((chip_scsi_id == i) ||
7229 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7230 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7231 continue;
7232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007233
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007234 len = asc_prt_line(cp, leftlen, " %X:", i);
7235 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007236
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007237 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7238 len = asc_prt_line(cp, leftlen, " Asynchronous");
7239 ASC_PRT_NEXT();
7240 } else {
7241 len =
7242 asc_prt_line(cp, leftlen,
7243 " Transfer Period Factor: ");
7244 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007245
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007246 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7247 len =
7248 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7249 ASC_PRT_NEXT();
7250 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7251 len =
7252 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7253 ASC_PRT_NEXT();
7254 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007255
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007256 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007257
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007258 if (period == 0) { /* Should never happen. */
7259 len =
7260 asc_prt_line(cp, leftlen,
7261 "%d (? Mhz), ");
7262 ASC_PRT_NEXT();
7263 } else {
7264 len = asc_prt_line(cp, leftlen,
7265 "%d (%d.%d Mhz),",
7266 period, 250 / period,
7267 ASC_TENTHS(250,
7268 period));
7269 ASC_PRT_NEXT();
7270 }
7271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007273 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7274 lramword & 0x1F);
7275 ASC_PRT_NEXT();
7276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007277
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007278 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7279 len = asc_prt_line(cp, leftlen, "*\n");
7280 renegotiate = 1;
7281 } else {
7282 len = asc_prt_line(cp, leftlen, "\n");
7283 }
7284 ASC_PRT_NEXT();
7285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007286
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007287 if (renegotiate) {
7288 len = asc_prt_line(cp, leftlen,
7289 " * = Re-negotiation pending before next command.\n");
7290 ASC_PRT_NEXT();
7291 }
7292
7293 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007294}
7295
7296/*
7297 * asc_proc_copy()
7298 *
7299 * Copy proc information to a read buffer taking into account the current
7300 * read offset in the file and the remaining space in the read buffer.
7301 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007302static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007303asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007304 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007305{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007306 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007308 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7309 (unsigned)offset, (unsigned)advoffset, cplen);
7310 if (offset <= advoffset) {
7311 /* Read offset below current offset, copy everything. */
7312 cnt = min(cplen, leftlen);
7313 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7314 (ulong)curbuf, (ulong)cp, cnt);
7315 memcpy(curbuf, cp, cnt);
7316 } else if (offset < advoffset + cplen) {
7317 /* Read offset within current range, partial copy. */
7318 cnt = (advoffset + cplen) - offset;
7319 cp = (cp + cplen) - cnt;
7320 cnt = min(cnt, leftlen);
7321 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7322 (ulong)curbuf, (ulong)cp, cnt);
7323 memcpy(curbuf, cp, cnt);
7324 }
7325 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007326}
7327
7328/*
7329 * asc_prt_line()
7330 *
7331 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7332 *
7333 * Return 0 if printing to the console, otherwise return the number of
7334 * bytes written to the buffer.
7335 *
7336 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7337 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7338 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007339static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007340{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007341 va_list args;
7342 int ret;
7343 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007344
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007345 va_start(args, fmt);
7346 ret = vsprintf(s, fmt, args);
7347 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7348 if (buf == NULL) {
7349 (void)printk(s);
7350 ret = 0;
7351 } else {
7352 ret = min(buflen, ret);
7353 memcpy(buf, s, ret);
7354 }
7355 va_end(args);
7356 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007357}
7358#endif /* CONFIG_PROC_FS */
7359
Linus Torvalds1da177e2005-04-16 15:20:36 -07007360/*
7361 * --- Functions Required by the Asc Library
7362 */
7363
7364/*
7365 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7366 * global variable which is incremented once every 5 ms
7367 * from a timer interrupt, because this function may be
7368 * called when interrupts are disabled.
7369 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007370static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007371{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007372 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7373 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007374}
7375
7376/*
7377 * Currently and inline noop but leave as a placeholder.
7378 * Leave DvcEnterCritical() as a noop placeholder.
7379 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007380static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007381{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007382 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007383}
7384
7385/*
7386 * Critical sections are all protected by the board spinlock.
7387 * Leave DvcLeaveCritical() as a noop placeholder.
7388 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007389static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007390{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007391 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007392}
7393
7394/*
7395 * void
7396 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7397 *
7398 * Calling/Exit State:
7399 * none
7400 *
7401 * Description:
7402 * Output an ASC_SCSI_Q structure to the chip
7403 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007404static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007405DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7406{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007407 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007408
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007409 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7410 AscSetChipLramAddr(iop_base, s_addr);
7411 for (i = 0; i < 2 * words; i += 2) {
7412 if (i == 4 || i == 20) {
7413 continue;
7414 }
7415 outpw(iop_base + IOP_RAM_DATA,
7416 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007418}
7419
7420/*
7421 * void
7422 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7423 *
7424 * Calling/Exit State:
7425 * none
7426 *
7427 * Description:
7428 * Input an ASC_QDONE_INFO structure from the chip
7429 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007430static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007431DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7432{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007433 int i;
7434 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007436 AscSetChipLramAddr(iop_base, s_addr);
7437 for (i = 0; i < 2 * words; i += 2) {
7438 if (i == 10) {
7439 continue;
7440 }
7441 word = inpw(iop_base + IOP_RAM_DATA);
7442 inbuf[i] = word & 0xff;
7443 inbuf[i + 1] = (word >> 8) & 0xff;
7444 }
7445 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007446}
7447
7448/*
7449 * Read a PCI configuration byte.
7450 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007451static uchar __init DvcReadPCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007452{
7453#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007454 uchar byte_data;
7455 pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
7456 return byte_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007457#else /* !defined(CONFIG_PCI) */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007458 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007459#endif /* !defined(CONFIG_PCI) */
7460}
7461
7462/*
7463 * Write a PCI configuration byte.
7464 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007465static void __init
7466DvcWritePCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007467{
7468#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007469 pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007470#endif /* CONFIG_PCI */
7471}
7472
7473/*
7474 * Return the BIOS address of the adapter at the specified
7475 * I/O port and with the specified bus type.
7476 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007477static ushort __init AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007478{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007479 ushort cfg_lsw;
7480 ushort bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007481
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007482 /*
7483 * The PCI BIOS is re-located by the motherboard BIOS. Because
7484 * of this the driver can not determine where a PCI BIOS is
7485 * loaded and executes.
7486 */
7487 if (bus_type & ASC_IS_PCI) {
7488 return (0);
7489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007490#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007491 if ((bus_type & ASC_IS_EISA) != 0) {
7492 cfg_lsw = AscGetEisaChipCfg(iop_base);
7493 cfg_lsw &= 0x000F;
7494 bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
7495 (cfg_lsw * ASC_BIOS_BANK_SIZE));
7496 return (bios_addr);
7497 } /* if */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007498#endif /* CONFIG_ISA */
7499
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007500 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007501
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007502 /*
7503 * ISA PnP uses the top bit as the 32K BIOS flag
7504 */
7505 if (bus_type == ASC_IS_ISAPNP) {
7506 cfg_lsw &= 0x7FFF;
7507 }
7508 /* if */
7509 bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
7510 ASC_BIOS_MIN_ADDR);
7511 return (bios_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007512}
7513
Linus Torvalds1da177e2005-04-16 15:20:36 -07007514/*
7515 * --- Functions Required by the Adv Library
7516 */
7517
7518/*
7519 * DvcGetPhyAddr()
7520 *
7521 * Return the physical address of 'vaddr' and set '*lenp' to the
7522 * number of physically contiguous bytes that follow 'vaddr'.
7523 * 'flag' indicates the type of structure whose physical address
7524 * is being translated.
7525 *
7526 * Note: Because Linux currently doesn't page the kernel and all
7527 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7528 */
7529ADV_PADDR
7530DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007531 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007532{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007533 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007534
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007535 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007536
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007537 ASC_DBG4(4,
7538 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7539 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7540 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007541
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007542 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007543}
7544
7545/*
7546 * Read a PCI configuration byte.
7547 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007548static uchar __init DvcAdvReadPCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007549{
7550#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007551 uchar byte_data;
7552 pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
7553 return byte_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007554#else /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007555 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007556#endif /* CONFIG_PCI */
7557}
7558
7559/*
7560 * Write a PCI configuration byte.
7561 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007562static void __init
7563DvcAdvWritePCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007564{
7565#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007566 pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007567#else /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007568 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007569#endif /* CONFIG_PCI */
7570}
7571
7572/*
7573 * --- Tracing and Debugging Functions
7574 */
7575
7576#ifdef ADVANSYS_STATS
7577#ifdef CONFIG_PROC_FS
7578/*
7579 * asc_prt_board_stats()
7580 *
7581 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7582 * cf. asc_prt_line().
7583 *
7584 * Return the number of characters copied into 'cp'. No more than
7585 * 'cplen' characters will be copied to 'cp'.
7586 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007587static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007588{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007589 int leftlen;
7590 int totlen;
7591 int len;
7592 struct asc_stats *s;
7593 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007594
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007595 leftlen = cplen;
7596 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007597
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007598 boardp = ASC_BOARDP(shost);
7599 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007600
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007601 len = asc_prt_line(cp, leftlen,
7602 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7603 shost->host_no);
7604 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007605
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007606 len = asc_prt_line(cp, leftlen,
7607 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7608 s->queuecommand, s->reset, s->biosparam,
7609 s->interrupt);
7610 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007611
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007612 len = asc_prt_line(cp, leftlen,
7613 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7614 s->callback, s->done, s->build_error,
7615 s->adv_build_noreq, s->adv_build_nosg);
7616 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007617
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007618 len = asc_prt_line(cp, leftlen,
7619 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7620 s->exe_noerror, s->exe_busy, s->exe_error,
7621 s->exe_unknown);
7622 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007623
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007624 /*
7625 * Display data transfer statistics.
7626 */
7627 if (s->cont_cnt > 0) {
7628 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7629 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007630
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007631 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7632 s->cont_xfer / 2,
7633 ASC_TENTHS(s->cont_xfer, 2));
7634 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007635
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007636 /* Contiguous transfer average size */
7637 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7638 (s->cont_xfer / 2) / s->cont_cnt,
7639 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7640 ASC_PRT_NEXT();
7641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007642
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007643 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007644
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007645 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7646 s->sg_cnt, s->sg_elem);
7647 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007648
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007649 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7650 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7651 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007652
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007653 /* Scatter gather transfer statistics */
7654 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7655 s->sg_elem / s->sg_cnt,
7656 ASC_TENTHS(s->sg_elem, s->sg_cnt));
7657 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007658
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007659 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
7660 (s->sg_xfer / 2) / s->sg_elem,
7661 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7662 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007663
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007664 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7665 (s->sg_xfer / 2) / s->sg_cnt,
7666 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7667 ASC_PRT_NEXT();
7668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007670 /*
7671 * Display request queuing statistics.
7672 */
7673 len = asc_prt_line(cp, leftlen,
7674 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7675 HZ);
7676 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007677
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007678 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007679}
7680
7681/*
7682 * asc_prt_target_stats()
7683 *
7684 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7685 * cf. asc_prt_line().
7686 *
7687 * This is separated from asc_prt_board_stats because a full set
7688 * of targets will overflow ASC_PRTBUF_SIZE.
7689 *
7690 * Return the number of characters copied into 'cp'. No more than
7691 * 'cplen' characters will be copied to 'cp'.
7692 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007693static int
7694asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007695{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007696 int leftlen;
7697 int totlen;
7698 int len;
7699 struct asc_stats *s;
7700 ushort chip_scsi_id;
7701 asc_board_t *boardp;
7702 asc_queue_t *active;
7703 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007704
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007705 leftlen = cplen;
7706 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007708 boardp = ASC_BOARDP(shost);
7709 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007710
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007711 active = &ASC_BOARDP(shost)->active;
7712 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007713
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007714 if (ASC_NARROW_BOARD(boardp)) {
7715 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7716 } else {
7717 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007719
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007720 if ((chip_scsi_id == tgt_id) ||
7721 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7722 return 0;
7723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007724
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007725 do {
7726 if (active->q_tot_cnt[tgt_id] > 0
7727 || waiting->q_tot_cnt[tgt_id] > 0) {
7728 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
7729 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007730
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007731 len = asc_prt_line(cp, leftlen,
7732 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7733 active->q_cur_cnt[tgt_id],
7734 active->q_max_cnt[tgt_id],
7735 active->q_tot_cnt[tgt_id],
7736 active->q_min_tim[tgt_id],
7737 active->q_max_tim[tgt_id],
7738 (active->q_tot_cnt[tgt_id] ==
7739 0) ? 0 : (active->
7740 q_tot_tim[tgt_id] /
7741 active->
7742 q_tot_cnt[tgt_id]),
7743 (active->q_tot_cnt[tgt_id] ==
7744 0) ? 0 : ASC_TENTHS(active->
7745 q_tot_tim
7746 [tgt_id],
7747 active->
7748 q_tot_cnt
7749 [tgt_id]));
7750 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007752 len = asc_prt_line(cp, leftlen,
7753 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7754 waiting->q_cur_cnt[tgt_id],
7755 waiting->q_max_cnt[tgt_id],
7756 waiting->q_tot_cnt[tgt_id],
7757 waiting->q_min_tim[tgt_id],
7758 waiting->q_max_tim[tgt_id],
7759 (waiting->q_tot_cnt[tgt_id] ==
7760 0) ? 0 : (waiting->
7761 q_tot_tim[tgt_id] /
7762 waiting->
7763 q_tot_cnt[tgt_id]),
7764 (waiting->q_tot_cnt[tgt_id] ==
7765 0) ? 0 : ASC_TENTHS(waiting->
7766 q_tot_tim
7767 [tgt_id],
7768 waiting->
7769 q_tot_cnt
7770 [tgt_id]));
7771 ASC_PRT_NEXT();
7772 }
7773 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007774
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007775 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007776}
7777#endif /* CONFIG_PROC_FS */
7778#endif /* ADVANSYS_STATS */
7779
7780#ifdef ADVANSYS_DEBUG
7781/*
7782 * asc_prt_scsi_host()
7783 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007784static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007785{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007786 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007787
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007788 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007790 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7791 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7792 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007793
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007794 printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
7795 (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007796
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007797 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7798 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007799
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007800 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7801 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007803 if (ASC_NARROW_BOARD(boardp)) {
7804 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7805 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7806 } else {
7807 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7808 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007810}
7811
7812/*
7813 * asc_prt_scsi_cmnd()
7814 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007815static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007816{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007817 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007818
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007819 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7820 (ulong)s->device->host, (ulong)s->device, s->device->id,
7821 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007822
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007823 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007824
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007825 printk("sc_data_direction %u, resid %d\n",
7826 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007827
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007828 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007829
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007830 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7831 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007832
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007833 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007834
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007835 printk
7836 (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
7837 (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble,
7838 s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007840 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007841}
7842
7843/*
7844 * asc_prt_asc_dvc_var()
7845 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007846static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007847{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007848 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007850 printk
7851 (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
7852 h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007854 printk
7855 (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
7856 h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback,
7857 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007859 printk
7860 (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
7861 (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng,
7862 (unsigned)h->unit_not_ready, (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007863
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007864 printk
7865 (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
7866 (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor,
7867 (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007868
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007869 printk
7870 (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
7871 (unsigned)h->is_in_int, (unsigned)h->max_total_qng,
7872 (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007873
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007874 printk
7875 (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
7876 (unsigned)h->last_q_shortage, (unsigned)h->init_state,
7877 (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007878
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007879 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007880}
7881
7882/*
7883 * asc_prt_asc_dvc_cfg()
7884 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007885static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007886{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007887 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007888
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007889 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7890 h->can_tagged_qng, h->cmd_qng_enabled);
7891 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7892 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007893
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007894 printk
7895 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7896 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7897 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007898
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007899 printk
7900 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7901 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7902 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007903
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007904 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7905 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007906}
7907
7908/*
7909 * asc_prt_asc_scsi_q()
7910 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007911static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007912{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007913 ASC_SG_HEAD *sgp;
7914 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007916 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007917
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007918 printk
7919 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7920 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7921 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007922
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007923 printk
7924 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7925 (ulong)le32_to_cpu(q->q1.data_addr),
7926 (ulong)le32_to_cpu(q->q1.data_cnt),
7927 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007929 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
7930 (ulong)q->cdbptr, q->q2.cdb_len,
7931 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007933 if (q->sg_head) {
7934 sgp = q->sg_head;
7935 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
7936 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
7937 sgp->queue_cnt);
7938 for (i = 0; i < sgp->entry_cnt; i++) {
7939 printk(" [%u]: addr 0x%lx, bytes %lu\n",
7940 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
7941 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
7942 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007945}
7946
7947/*
7948 * asc_prt_asc_qdone_info()
7949 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007950static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007951{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007952 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
7953 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
7954 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
7955 q->d2.tag_code);
7956 printk
7957 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
7958 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007959}
7960
7961/*
7962 * asc_prt_adv_dvc_var()
7963 *
7964 * Display an ADV_DVC_VAR structure.
7965 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007966static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007967{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007968 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007969
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007970 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
7971 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007972
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007973 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
7974 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
7975 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007976
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007977 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
7978 (unsigned)h->start_motor,
7979 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007980
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007981 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
7982 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
7983 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007984
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007985 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
7986 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007987
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007988 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
7989 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007990
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007991 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
7992 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007993}
7994
7995/*
7996 * asc_prt_adv_dvc_cfg()
7997 *
7998 * Display an ADV_DVC_CFG structure.
7999 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008000static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008001{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008002 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008004 printk(" disc_enable 0x%x, termination 0x%x\n",
8005 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008006
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008007 printk(" chip_version 0x%x, mcode_date 0x%x\n",
8008 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008009
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008010 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
8011 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008012
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008013 printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
8014 h->control_flag, h->pci_slot_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008015}
8016
8017/*
8018 * asc_prt_adv_scsi_req_q()
8019 *
8020 * Display an ADV_SCSI_REQ_Q structure.
8021 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008022static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008023{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008024 int sg_blk_cnt;
8025 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008027 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008029 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
8030 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008031
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008032 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
8033 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008034
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008035 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
8036 (ulong)le32_to_cpu(q->data_cnt),
8037 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008038
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008039 printk
8040 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
8041 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008043 printk(" sg_working_ix 0x%x, target_cmd %u\n",
8044 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008045
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008046 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
8047 (ulong)le32_to_cpu(q->scsiq_rptr),
8048 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008049
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008050 /* Display the request's ADV_SG_BLOCK structures. */
8051 if (q->sg_list_ptr != NULL) {
8052 sg_blk_cnt = 0;
8053 while (1) {
8054 /*
8055 * 'sg_ptr' is a physical address. Convert it to a virtual
8056 * address by indexing 'sg_blk_cnt' into the virtual address
8057 * array 'sg_list_ptr'.
8058 *
8059 * XXX - Assumes all SG physical blocks are virtually contiguous.
8060 */
8061 sg_ptr =
8062 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
8063 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
8064 if (sg_ptr->sg_ptr == 0) {
8065 break;
8066 }
8067 sg_blk_cnt++;
8068 }
8069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008070}
8071
8072/*
8073 * asc_prt_adv_sgblock()
8074 *
8075 * Display an ADV_SG_BLOCK structure.
8076 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008077static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008078{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008079 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008081 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
8082 (ulong)b, sgblockno);
8083 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
8084 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
8085 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
8086 if (b->sg_ptr != 0) {
8087 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
8088 }
8089 for (i = 0; i < b->sg_cnt; i++) {
8090 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
8091 i, (ulong)b->sg_list[i].sg_addr,
8092 (ulong)b->sg_list[i].sg_count);
8093 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008094}
8095
8096/*
8097 * asc_prt_hex()
8098 *
8099 * Print hexadecimal output in 4 byte groupings 32 bytes
8100 * or 8 double-words per line.
8101 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008102static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008103{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008104 int i;
8105 int j;
8106 int k;
8107 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008109 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008110
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008111 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008113 /* Display a maximum of 8 double-words per line. */
8114 if ((k = (l - i) / 4) >= 8) {
8115 k = 8;
8116 m = 0;
8117 } else {
8118 m = (l - i) % 4;
8119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008120
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008121 for (j = 0; j < k; j++) {
8122 printk(" %2.2X%2.2X%2.2X%2.2X",
8123 (unsigned)s[i + (j * 4)],
8124 (unsigned)s[i + (j * 4) + 1],
8125 (unsigned)s[i + (j * 4) + 2],
8126 (unsigned)s[i + (j * 4) + 3]);
8127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008128
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008129 switch (m) {
8130 case 0:
8131 default:
8132 break;
8133 case 1:
8134 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
8135 break;
8136 case 2:
8137 printk(" %2.2X%2.2X",
8138 (unsigned)s[i + (j * 4)],
8139 (unsigned)s[i + (j * 4) + 1]);
8140 break;
8141 case 3:
8142 printk(" %2.2X%2.2X%2.2X",
8143 (unsigned)s[i + (j * 4) + 1],
8144 (unsigned)s[i + (j * 4) + 2],
8145 (unsigned)s[i + (j * 4) + 3]);
8146 break;
8147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008148
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008149 printk("\n");
8150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008151}
8152#endif /* ADVANSYS_DEBUG */
8153
8154/*
8155 * --- Asc Library Functions
8156 */
8157
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008158static ushort __init AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008159{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008160 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008161
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008162 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
8163 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
8164 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008165}
8166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008167static uchar __init AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008168{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008169 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008170
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008171 if (AscGetChipScsiID(iop_base) == new_host_id) {
8172 return (new_host_id);
8173 }
8174 cfg_lsw = AscGetChipCfgLsw(iop_base);
8175 cfg_lsw &= 0xF8FF;
8176 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
8177 AscSetChipCfgLsw(iop_base, cfg_lsw);
8178 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008179}
8180
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008181static uchar __init AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008182{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008183 uchar sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008184
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008185 AscSetBank(iop_base, 1);
8186 sc = inp(iop_base + IOP_REG_SC);
8187 AscSetBank(iop_base, 0);
8188 return (sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008189}
8190
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008191static uchar __init AscGetChipVersion(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008192{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008193 if ((bus_type & ASC_IS_EISA) != 0) {
8194 PortAddr eisa_iop;
8195 uchar revision;
8196 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
8197 (PortAddr) ASC_EISA_REV_IOP_MASK;
8198 revision = inp(eisa_iop);
8199 return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision));
8200 }
8201 return (AscGetChipVerNo(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008202}
8203
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008204static ushort __init AscGetChipBusType(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008205{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008206 ushort chip_ver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008207
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008208 chip_ver = AscGetChipVerNo(iop_base);
8209 if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
8210 && (chip_ver <= ASC_CHIP_MAX_VER_VL)
8211 ) {
8212 if (((iop_base & 0x0C30) == 0x0C30)
8213 || ((iop_base & 0x0C50) == 0x0C50)
8214 ) {
8215 return (ASC_IS_EISA);
8216 }
8217 return (ASC_IS_VL);
8218 }
8219 if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
8220 (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
8221 if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
8222 return (ASC_IS_ISAPNP);
8223 }
8224 return (ASC_IS_ISA);
8225 } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
8226 (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
8227 return (ASC_IS_PCI);
8228 }
8229 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008230}
8231
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008232static ASC_DCNT
8233AscLoadMicroCode(PortAddr iop_base,
8234 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008235{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008236 ASC_DCNT chksum;
8237 ushort mcode_word_size;
8238 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008239
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008240 /* Write the microcode buffer starting at LRAM address 0. */
8241 mcode_word_size = (ushort)(mcode_size >> 1);
8242 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
8243 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008244
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008245 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
8246 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
8247 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
8248 (ushort)ASC_CODE_SEC_BEG,
8249 (ushort)((mcode_size -
8250 s_addr - (ushort)
8251 ASC_CODE_SEC_BEG) /
8252 2));
8253 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
8254 (ulong)mcode_chksum);
8255 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
8256 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
8257 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008258}
8259
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008260static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008261{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008262 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008263
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008264 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
8265 iop_base, AscGetChipSignatureByte(iop_base));
8266 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
8267 ASC_DBG2(1,
8268 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
8269 iop_base, AscGetChipSignatureWord(iop_base));
8270 sig_word = AscGetChipSignatureWord(iop_base);
8271 if ((sig_word == (ushort)ASC_1000_ID0W) ||
8272 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
8273 return (1);
8274 }
8275 }
8276 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008277}
8278
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008279static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata = {
8280 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
8281 ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
Linus Torvalds1da177e2005-04-16 15:20:36 -07008282};
8283
8284#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008285static uchar _isa_pnp_inited __initdata = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008286
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008287static PortAddr __init AscSearchIOPortAddr(PortAddr iop_beg, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008288{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008289 if (bus_type & ASC_IS_VL) {
8290 while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
8291 if (AscGetChipVersion(iop_beg, bus_type) <=
8292 ASC_CHIP_MAX_VER_VL) {
8293 return (iop_beg);
8294 }
8295 }
8296 return (0);
8297 }
8298 if (bus_type & ASC_IS_ISA) {
8299 if (_isa_pnp_inited == 0) {
8300 AscSetISAPNPWaitForKey();
8301 _isa_pnp_inited++;
8302 }
8303 while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
8304 if ((AscGetChipVersion(iop_beg, bus_type) &
8305 ASC_CHIP_VER_ISA_BIT) != 0) {
8306 return (iop_beg);
8307 }
8308 }
8309 return (0);
8310 }
8311 if (bus_type & ASC_IS_EISA) {
8312 if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
8313 return (iop_beg);
8314 }
8315 return (0);
8316 }
8317 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008318}
8319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008320static PortAddr __init AscSearchIOPortAddr11(PortAddr s_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008321{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008322 int i;
8323 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008324
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008325 for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
8326 if (_asc_def_iop_base[i] > s_addr) {
8327 break;
8328 }
8329 }
8330 for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
8331 iop_base = _asc_def_iop_base[i];
8332 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
8333 ASC_DBG1(1,
8334 "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
8335 iop_base);
8336 continue;
8337 }
8338 ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n",
8339 iop_base);
8340 release_region(iop_base, ASC_IOADR_GAP);
8341 if (AscFindSignature(iop_base)) {
8342 return (iop_base);
8343 }
8344 }
8345 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008346}
8347
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008348static void __init AscSetISAPNPWaitForKey(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008349{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008350 outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
8351 outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
8352 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008353}
8354#endif /* CONFIG_ISA */
8355
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008356static void __init AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008357{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008358 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
8359 AscSetChipStatus(iop_base, 0);
8360 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008361}
8362
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008363static uchar __init AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008364{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008365 ushort cfg_lsw;
8366 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008367
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008368 if ((bus_type & ASC_IS_EISA) != 0) {
8369 cfg_lsw = AscGetEisaChipCfg(iop_base);
8370 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8371 if ((chip_irq == 13) || (chip_irq > 15)) {
8372 return (0);
8373 }
8374 return (chip_irq);
8375 }
8376 if ((bus_type & ASC_IS_VL) != 0) {
8377 cfg_lsw = AscGetChipCfgLsw(iop_base);
8378 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8379 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8380 return (0);
8381 }
8382 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8383 }
8384 cfg_lsw = AscGetChipCfgLsw(iop_base);
8385 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8386 if (chip_irq == 3)
8387 chip_irq += (uchar)2;
8388 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008389}
8390
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008391static uchar __init
8392AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008393{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008394 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008395
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008396 if ((bus_type & ASC_IS_VL) != 0) {
8397 if (irq_no != 0) {
8398 if ((irq_no < ASC_MIN_IRQ_NO)
8399 || (irq_no > ASC_MAX_IRQ_NO)) {
8400 irq_no = 0;
8401 } else {
8402 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8403 }
8404 }
8405 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8406 cfg_lsw |= (ushort)0x0010;
8407 AscSetChipCfgLsw(iop_base, cfg_lsw);
8408 AscToggleIRQAct(iop_base);
8409 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8410 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8411 AscSetChipCfgLsw(iop_base, cfg_lsw);
8412 AscToggleIRQAct(iop_base);
8413 return (AscGetChipIRQ(iop_base, bus_type));
8414 }
8415 if ((bus_type & (ASC_IS_ISA)) != 0) {
8416 if (irq_no == 15)
8417 irq_no -= (uchar)2;
8418 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8419 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8420 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8421 AscSetChipCfgLsw(iop_base, cfg_lsw);
8422 return (AscGetChipIRQ(iop_base, bus_type));
8423 }
8424 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008425}
8426
8427#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008428static void __init AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008429{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008430 if (dma_channel < 4) {
8431 outp(0x000B, (ushort)(0xC0 | dma_channel));
8432 outp(0x000A, dma_channel);
8433 } else if (dma_channel < 8) {
8434 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8435 outp(0x00D4, (ushort)(dma_channel - 4));
8436 }
8437 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008438}
8439#endif /* CONFIG_ISA */
8440
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008441static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008442{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008443 EXT_MSG ext_msg;
8444 EXT_MSG out_msg;
8445 ushort halt_q_addr;
8446 int sdtr_accept;
8447 ushort int_halt_code;
8448 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8449 ASC_SCSI_BIT_ID_TYPE target_id;
8450 PortAddr iop_base;
8451 uchar tag_code;
8452 uchar q_status;
8453 uchar halt_qp;
8454 uchar sdtr_data;
8455 uchar target_ix;
8456 uchar q_cntl, tid_no;
8457 uchar cur_dvc_qng;
8458 uchar asyn_sdtr;
8459 uchar scsi_status;
8460 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008461
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008462 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8463 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008464
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008465 iop_base = asc_dvc->iop_base;
8466 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008467
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008468 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8469 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8470 target_ix = AscReadLramByte(iop_base,
8471 (ushort)(halt_q_addr +
8472 (ushort)ASC_SCSIQ_B_TARGET_IX));
8473 q_cntl =
8474 AscReadLramByte(iop_base,
8475 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8476 tid_no = ASC_TIX_TO_TID(target_ix);
8477 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8478 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8479 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8480 } else {
8481 asyn_sdtr = 0;
8482 }
8483 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8484 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8485 AscSetChipSDTR(iop_base, 0, tid_no);
8486 boardp->sdtr_data[tid_no] = 0;
8487 }
8488 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8489 return (0);
8490 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8491 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8492 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8493 boardp->sdtr_data[tid_no] = asyn_sdtr;
8494 }
8495 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8496 return (0);
8497 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008498
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008499 AscMemWordCopyPtrFromLram(iop_base,
8500 ASCV_MSGIN_BEG,
8501 (uchar *)&ext_msg,
8502 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008503
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008504 if (ext_msg.msg_type == MS_EXTEND &&
8505 ext_msg.msg_req == MS_SDTR_CODE &&
8506 ext_msg.msg_len == MS_SDTR_LEN) {
8507 sdtr_accept = TRUE;
8508 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008509
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008510 sdtr_accept = FALSE;
8511 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8512 }
8513 if ((ext_msg.xfer_period <
8514 asc_dvc->sdtr_period_tbl[asc_dvc->
8515 host_init_sdtr_index])
8516 || (ext_msg.xfer_period >
8517 asc_dvc->sdtr_period_tbl[asc_dvc->
8518 max_sdtr_index])) {
8519 sdtr_accept = FALSE;
8520 ext_msg.xfer_period =
8521 asc_dvc->sdtr_period_tbl[asc_dvc->
8522 host_init_sdtr_index];
8523 }
8524 if (sdtr_accept) {
8525 sdtr_data =
8526 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8527 ext_msg.req_ack_offset);
8528 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008529
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008530 q_cntl |= QC_MSG_OUT;
8531 asc_dvc->init_sdtr &= ~target_id;
8532 asc_dvc->sdtr_done &= ~target_id;
8533 AscSetChipSDTR(iop_base, asyn_sdtr,
8534 tid_no);
8535 boardp->sdtr_data[tid_no] = asyn_sdtr;
8536 }
8537 }
8538 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008539
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008540 q_cntl &= ~QC_MSG_OUT;
8541 asc_dvc->init_sdtr &= ~target_id;
8542 asc_dvc->sdtr_done &= ~target_id;
8543 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8544 } else {
8545 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008546
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008547 q_cntl &= ~QC_MSG_OUT;
8548 asc_dvc->sdtr_done |= target_id;
8549 asc_dvc->init_sdtr |= target_id;
8550 asc_dvc->pci_fix_asyn_xfer &=
8551 ~target_id;
8552 sdtr_data =
8553 AscCalSDTRData(asc_dvc,
8554 ext_msg.xfer_period,
8555 ext_msg.
8556 req_ack_offset);
8557 AscSetChipSDTR(iop_base, sdtr_data,
8558 tid_no);
8559 boardp->sdtr_data[tid_no] = sdtr_data;
8560 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008561
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008562 q_cntl |= QC_MSG_OUT;
8563 AscMsgOutSDTR(asc_dvc,
8564 ext_msg.xfer_period,
8565 ext_msg.req_ack_offset);
8566 asc_dvc->pci_fix_asyn_xfer &=
8567 ~target_id;
8568 sdtr_data =
8569 AscCalSDTRData(asc_dvc,
8570 ext_msg.xfer_period,
8571 ext_msg.
8572 req_ack_offset);
8573 AscSetChipSDTR(iop_base, sdtr_data,
8574 tid_no);
8575 boardp->sdtr_data[tid_no] = sdtr_data;
8576 asc_dvc->sdtr_done |= target_id;
8577 asc_dvc->init_sdtr |= target_id;
8578 }
8579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008580
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008581 AscWriteLramByte(iop_base,
8582 (ushort)(halt_q_addr +
8583 (ushort)ASC_SCSIQ_B_CNTL),
8584 q_cntl);
8585 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8586 return (0);
8587 } else if (ext_msg.msg_type == MS_EXTEND &&
8588 ext_msg.msg_req == MS_WDTR_CODE &&
8589 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008590
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008591 ext_msg.wdtr_width = 0;
8592 AscMemWordCopyPtrToLram(iop_base,
8593 ASCV_MSGOUT_BEG,
8594 (uchar *)&ext_msg,
8595 sizeof(EXT_MSG) >> 1);
8596 q_cntl |= QC_MSG_OUT;
8597 AscWriteLramByte(iop_base,
8598 (ushort)(halt_q_addr +
8599 (ushort)ASC_SCSIQ_B_CNTL),
8600 q_cntl);
8601 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8602 return (0);
8603 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008604
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008605 ext_msg.msg_type = MESSAGE_REJECT;
8606 AscMemWordCopyPtrToLram(iop_base,
8607 ASCV_MSGOUT_BEG,
8608 (uchar *)&ext_msg,
8609 sizeof(EXT_MSG) >> 1);
8610 q_cntl |= QC_MSG_OUT;
8611 AscWriteLramByte(iop_base,
8612 (ushort)(halt_q_addr +
8613 (ushort)ASC_SCSIQ_B_CNTL),
8614 q_cntl);
8615 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8616 return (0);
8617 }
8618 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008619
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008620 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008621
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008622 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008623
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008624 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008625
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008626 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8627 q_cntl |= QC_MSG_OUT;
8628 AscMsgOutSDTR(asc_dvc,
8629 asc_dvc->
8630 sdtr_period_tbl[(sdtr_data >> 4) &
8631 (uchar)(asc_dvc->
8632 max_sdtr_index -
8633 1)],
8634 (uchar)(sdtr_data & (uchar)
8635 ASC_SYN_MAX_OFFSET));
8636 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008637
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008638 AscWriteLramByte(iop_base,
8639 (ushort)(halt_q_addr +
8640 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008641
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008642 tag_code = AscReadLramByte(iop_base,
8643 (ushort)(halt_q_addr + (ushort)
8644 ASC_SCSIQ_B_TAG_CODE));
8645 tag_code &= 0xDC;
8646 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8647 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8648 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008649
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008650 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8651 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008652
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008653 }
8654 AscWriteLramByte(iop_base,
8655 (ushort)(halt_q_addr +
8656 (ushort)ASC_SCSIQ_B_TAG_CODE),
8657 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008658
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008659 q_status = AscReadLramByte(iop_base,
8660 (ushort)(halt_q_addr + (ushort)
8661 ASC_SCSIQ_B_STATUS));
8662 q_status |= (QS_READY | QS_BUSY);
8663 AscWriteLramByte(iop_base,
8664 (ushort)(halt_q_addr +
8665 (ushort)ASC_SCSIQ_B_STATUS),
8666 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008668 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8669 scsi_busy &= ~target_id;
8670 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008672 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8673 return (0);
8674 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008676 AscMemWordCopyPtrFromLram(iop_base,
8677 ASCV_MSGOUT_BEG,
8678 (uchar *)&out_msg,
8679 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008680
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008681 if ((out_msg.msg_type == MS_EXTEND) &&
8682 (out_msg.msg_len == MS_SDTR_LEN) &&
8683 (out_msg.msg_req == MS_SDTR_CODE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008684
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008685 asc_dvc->init_sdtr &= ~target_id;
8686 asc_dvc->sdtr_done &= ~target_id;
8687 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8688 boardp->sdtr_data[tid_no] = asyn_sdtr;
8689 }
8690 q_cntl &= ~QC_MSG_OUT;
8691 AscWriteLramByte(iop_base,
8692 (ushort)(halt_q_addr +
8693 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8694 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8695 return (0);
8696 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008698 scsi_status = AscReadLramByte(iop_base,
8699 (ushort)((ushort)halt_q_addr +
8700 (ushort)
8701 ASC_SCSIQ_SCSI_STATUS));
8702 cur_dvc_qng =
8703 AscReadLramByte(iop_base,
8704 (ushort)((ushort)ASC_QADR_BEG +
8705 (ushort)target_ix));
8706 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008708 scsi_busy = AscReadLramByte(iop_base,
8709 (ushort)ASCV_SCSIBUSY_B);
8710 scsi_busy |= target_id;
8711 AscWriteLramByte(iop_base,
8712 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8713 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008714
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008715 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8716 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8717 cur_dvc_qng -= 1;
8718 asc_dvc->max_dvc_qng[tid_no] =
8719 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008720
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008721 AscWriteLramByte(iop_base,
8722 (ushort)((ushort)
8723 ASCV_MAX_DVC_QNG_BEG
8724 + (ushort)
8725 tid_no),
8726 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008727
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008728 /*
8729 * Set the device queue depth to the number of
8730 * active requests when the QUEUE FULL condition
8731 * was encountered.
8732 */
8733 boardp->queue_full |= target_id;
8734 boardp->queue_full_cnt[tid_no] =
8735 cur_dvc_qng;
8736 }
8737 }
8738 }
8739 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8740 return (0);
8741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008742#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008743 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8744 uchar q_no;
8745 ushort q_addr;
8746 uchar sg_wk_q_no;
8747 uchar first_sg_wk_q_no;
8748 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8749 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8750 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8751 ushort sg_list_dwords;
8752 ushort sg_entry_cnt;
8753 uchar next_qp;
8754 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008755
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008756 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8757 if (q_no == ASC_QLINK_END) {
8758 return (0);
8759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008760
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008761 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008763 /*
8764 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8765 * structure pointer using a macro provided by the driver.
8766 * The ASC_SCSI_REQ pointer provides a pointer to the
8767 * host ASC_SG_HEAD structure.
8768 */
8769 /* Read request's SRB pointer. */
8770 scsiq = (ASC_SCSI_Q *)
8771 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8772 (ushort)
8773 (q_addr +
8774 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008776 /*
8777 * Get request's first and working SG queue.
8778 */
8779 sg_wk_q_no = AscReadLramByte(iop_base,
8780 (ushort)(q_addr +
8781 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008782
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008783 first_sg_wk_q_no = AscReadLramByte(iop_base,
8784 (ushort)(q_addr +
8785 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008787 /*
8788 * Reset request's working SG queue back to the
8789 * first SG queue.
8790 */
8791 AscWriteLramByte(iop_base,
8792 (ushort)(q_addr +
8793 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8794 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008796 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008797
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008798 /*
8799 * Set sg_entry_cnt to the number of SG elements
8800 * that will be completed on this interrupt.
8801 *
8802 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8803 * SG elements. The data_cnt and data_addr fields which
8804 * add 1 to the SG element capacity are not used when
8805 * restarting SG handling after a halt.
8806 */
8807 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8808 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008810 /*
8811 * Keep track of remaining number of SG elements that will
8812 * need to be handled on the next interrupt.
8813 */
8814 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8815 } else {
8816 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8817 scsiq->remain_sg_entry_cnt = 0;
8818 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008819
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008820 /*
8821 * Copy SG elements into the list of allocated SG queues.
8822 *
8823 * Last index completed is saved in scsiq->next_sg_index.
8824 */
8825 next_qp = first_sg_wk_q_no;
8826 q_addr = ASC_QNO_TO_QADDR(next_qp);
8827 scsi_sg_q.sg_head_qp = q_no;
8828 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8829 for (i = 0; i < sg_head->queue_cnt; i++) {
8830 scsi_sg_q.seq_no = i + 1;
8831 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8832 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8833 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8834 /*
8835 * After very first SG queue RISC FW uses next
8836 * SG queue first element then checks sg_list_cnt
8837 * against zero and then decrements, so set
8838 * sg_list_cnt 1 less than number of SG elements
8839 * in each SG queue.
8840 */
8841 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8842 scsi_sg_q.sg_cur_list_cnt =
8843 ASC_SG_LIST_PER_Q - 1;
8844 } else {
8845 /*
8846 * This is the last SG queue in the list of
8847 * allocated SG queues. If there are more
8848 * SG elements than will fit in the allocated
8849 * queues, then set the QCSG_SG_XFER_MORE flag.
8850 */
8851 if (scsiq->remain_sg_entry_cnt != 0) {
8852 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8853 } else {
8854 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8855 }
8856 /* equals sg_entry_cnt * 2 */
8857 sg_list_dwords = sg_entry_cnt << 1;
8858 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8859 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8860 sg_entry_cnt = 0;
8861 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008862
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008863 scsi_sg_q.q_no = next_qp;
8864 AscMemWordCopyPtrToLram(iop_base,
8865 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8866 (uchar *)&scsi_sg_q,
8867 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008868
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008869 AscMemDWordCopyPtrToLram(iop_base,
8870 q_addr + ASC_SGQ_LIST_BEG,
8871 (uchar *)&sg_head->
8872 sg_list[scsiq->next_sg_index],
8873 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008874
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008875 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008876
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008877 /*
8878 * If the just completed SG queue contained the
8879 * last SG element, then no more SG queues need
8880 * to be written.
8881 */
8882 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8883 break;
8884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008885
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008886 next_qp = AscReadLramByte(iop_base,
8887 (ushort)(q_addr +
8888 ASC_SCSIQ_B_FWD));
8889 q_addr = ASC_QNO_TO_QADDR(next_qp);
8890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008891
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008892 /*
8893 * Clear the halt condition so the RISC will be restarted
8894 * after the return.
8895 */
8896 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8897 return (0);
8898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008899#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008900 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008901}
8902
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008903static uchar
8904_AscCopyLramScsiDoneQ(PortAddr iop_base,
8905 ushort q_addr,
8906 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008907{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008908 ushort _val;
8909 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008910
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008911 DvcGetQinfo(iop_base,
8912 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8913 (uchar *)scsiq,
8914 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008916 _val = AscReadLramWord(iop_base,
8917 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8918 scsiq->q_status = (uchar)_val;
8919 scsiq->q_no = (uchar)(_val >> 8);
8920 _val = AscReadLramWord(iop_base,
8921 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8922 scsiq->cntl = (uchar)_val;
8923 sg_queue_cnt = (uchar)(_val >> 8);
8924 _val = AscReadLramWord(iop_base,
8925 (ushort)(q_addr +
8926 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8927 scsiq->sense_len = (uchar)_val;
8928 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008930 /*
8931 * Read high word of remain bytes from alternate location.
8932 */
8933 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
8934 (ushort)(q_addr +
8935 (ushort)
8936 ASC_SCSIQ_W_ALT_DC1)))
8937 << 16);
8938 /*
8939 * Read low word of remain bytes from original location.
8940 */
8941 scsiq->remain_bytes += AscReadLramWord(iop_base,
8942 (ushort)(q_addr + (ushort)
8943 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008944
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008945 scsiq->remain_bytes &= max_dma_count;
8946 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008947}
8948
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008949static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008950{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008951 uchar next_qp;
8952 uchar n_q_used;
8953 uchar sg_list_qp;
8954 uchar sg_queue_cnt;
8955 uchar q_cnt;
8956 uchar done_q_tail;
8957 uchar tid_no;
8958 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8959 ASC_SCSI_BIT_ID_TYPE target_id;
8960 PortAddr iop_base;
8961 ushort q_addr;
8962 ushort sg_q_addr;
8963 uchar cur_target_qng;
8964 ASC_QDONE_INFO scsiq_buf;
8965 ASC_QDONE_INFO *scsiq;
8966 int false_overrun;
8967 ASC_ISR_CALLBACK asc_isr_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008968
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008969 iop_base = asc_dvc->iop_base;
8970 asc_isr_callback = asc_dvc->isr_callback;
8971 n_q_used = 1;
8972 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
8973 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
8974 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
8975 next_qp = AscReadLramByte(iop_base,
8976 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
8977 if (next_qp != ASC_QLINK_END) {
8978 AscPutVarDoneQTail(iop_base, next_qp);
8979 q_addr = ASC_QNO_TO_QADDR(next_qp);
8980 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
8981 asc_dvc->max_dma_count);
8982 AscWriteLramByte(iop_base,
8983 (ushort)(q_addr +
8984 (ushort)ASC_SCSIQ_B_STATUS),
8985 (uchar)(scsiq->
8986 q_status & (uchar)~(QS_READY |
8987 QS_ABORTED)));
8988 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
8989 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
8990 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
8991 sg_q_addr = q_addr;
8992 sg_list_qp = next_qp;
8993 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
8994 sg_list_qp = AscReadLramByte(iop_base,
8995 (ushort)(sg_q_addr
8996 + (ushort)
8997 ASC_SCSIQ_B_FWD));
8998 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
8999 if (sg_list_qp == ASC_QLINK_END) {
9000 AscSetLibErrorCode(asc_dvc,
9001 ASCQ_ERR_SG_Q_LINKS);
9002 scsiq->d3.done_stat = QD_WITH_ERROR;
9003 scsiq->d3.host_stat =
9004 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
9005 goto FATAL_ERR_QDONE;
9006 }
9007 AscWriteLramByte(iop_base,
9008 (ushort)(sg_q_addr + (ushort)
9009 ASC_SCSIQ_B_STATUS),
9010 QS_FREE);
9011 }
9012 n_q_used = sg_queue_cnt + 1;
9013 AscPutVarDoneQTail(iop_base, sg_list_qp);
9014 }
9015 if (asc_dvc->queue_full_or_busy & target_id) {
9016 cur_target_qng = AscReadLramByte(iop_base,
9017 (ushort)((ushort)
9018 ASC_QADR_BEG
9019 + (ushort)
9020 scsiq->d2.
9021 target_ix));
9022 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
9023 scsi_busy = AscReadLramByte(iop_base, (ushort)
9024 ASCV_SCSIBUSY_B);
9025 scsi_busy &= ~target_id;
9026 AscWriteLramByte(iop_base,
9027 (ushort)ASCV_SCSIBUSY_B,
9028 scsi_busy);
9029 asc_dvc->queue_full_or_busy &= ~target_id;
9030 }
9031 }
9032 if (asc_dvc->cur_total_qng >= n_q_used) {
9033 asc_dvc->cur_total_qng -= n_q_used;
9034 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
9035 asc_dvc->cur_dvc_qng[tid_no]--;
9036 }
9037 } else {
9038 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
9039 scsiq->d3.done_stat = QD_WITH_ERROR;
9040 goto FATAL_ERR_QDONE;
9041 }
9042 if ((scsiq->d2.srb_ptr == 0UL) ||
9043 ((scsiq->q_status & QS_ABORTED) != 0)) {
9044 return (0x11);
9045 } else if (scsiq->q_status == QS_DONE) {
9046 false_overrun = FALSE;
9047 if (scsiq->extra_bytes != 0) {
9048 scsiq->remain_bytes +=
9049 (ADV_DCNT)scsiq->extra_bytes;
9050 }
9051 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
9052 if (scsiq->d3.host_stat ==
9053 QHSTA_M_DATA_OVER_RUN) {
9054 if ((scsiq->
9055 cntl & (QC_DATA_IN | QC_DATA_OUT))
9056 == 0) {
9057 scsiq->d3.done_stat =
9058 QD_NO_ERROR;
9059 scsiq->d3.host_stat =
9060 QHSTA_NO_ERROR;
9061 } else if (false_overrun) {
9062 scsiq->d3.done_stat =
9063 QD_NO_ERROR;
9064 scsiq->d3.host_stat =
9065 QHSTA_NO_ERROR;
9066 }
9067 } else if (scsiq->d3.host_stat ==
9068 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
9069 AscStopChip(iop_base);
9070 AscSetChipControl(iop_base,
9071 (uchar)(CC_SCSI_RESET
9072 | CC_HALT));
9073 DvcDelayNanoSecond(asc_dvc, 60000);
9074 AscSetChipControl(iop_base, CC_HALT);
9075 AscSetChipStatus(iop_base,
9076 CIW_CLR_SCSI_RESET_INT);
9077 AscSetChipStatus(iop_base, 0);
9078 AscSetChipControl(iop_base, 0);
9079 }
9080 }
9081 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
9082 (*asc_isr_callback) (asc_dvc, scsiq);
9083 } else {
9084 if ((AscReadLramByte(iop_base,
9085 (ushort)(q_addr + (ushort)
9086 ASC_SCSIQ_CDB_BEG))
9087 == START_STOP)) {
9088 asc_dvc->unit_not_ready &= ~target_id;
9089 if (scsiq->d3.done_stat != QD_NO_ERROR) {
9090 asc_dvc->start_motor &=
9091 ~target_id;
9092 }
9093 }
9094 }
9095 return (1);
9096 } else {
9097 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
9098 FATAL_ERR_QDONE:
9099 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
9100 (*asc_isr_callback) (asc_dvc, scsiq);
9101 }
9102 return (0x80);
9103 }
9104 }
9105 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009106}
9107
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009108static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009109{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009110 ASC_CS_TYPE chipstat;
9111 PortAddr iop_base;
9112 ushort saved_ram_addr;
9113 uchar ctrl_reg;
9114 uchar saved_ctrl_reg;
9115 int int_pending;
9116 int status;
9117 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009118
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009119 iop_base = asc_dvc->iop_base;
9120 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009121
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009122 if (AscIsIntPending(iop_base) == 0) {
9123 return int_pending;
9124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009125
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009126 if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
9127 || (asc_dvc->isr_callback == 0)
9128 ) {
9129 return (ERR);
9130 }
9131 if (asc_dvc->in_critical_cnt != 0) {
9132 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
9133 return (ERR);
9134 }
9135 if (asc_dvc->is_in_int) {
9136 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
9137 return (ERR);
9138 }
9139 asc_dvc->is_in_int = TRUE;
9140 ctrl_reg = AscGetChipControl(iop_base);
9141 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
9142 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
9143 chipstat = AscGetChipStatus(iop_base);
9144 if (chipstat & CSW_SCSI_RESET_LATCH) {
9145 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
9146 int i = 10;
9147 int_pending = TRUE;
9148 asc_dvc->sdtr_done = 0;
9149 saved_ctrl_reg &= (uchar)(~CC_HALT);
9150 while ((AscGetChipStatus(iop_base) &
9151 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
9152 DvcSleepMilliSecond(100);
9153 }
9154 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
9155 AscSetChipControl(iop_base, CC_HALT);
9156 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
9157 AscSetChipStatus(iop_base, 0);
9158 chipstat = AscGetChipStatus(iop_base);
9159 }
9160 }
9161 saved_ram_addr = AscGetChipLramAddr(iop_base);
9162 host_flag = AscReadLramByte(iop_base,
9163 ASCV_HOST_FLAG_B) &
9164 (uchar)(~ASC_HOST_FLAG_IN_ISR);
9165 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
9166 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
9167 if ((chipstat & CSW_INT_PENDING)
9168 || (int_pending)
9169 ) {
9170 AscAckInterrupt(iop_base);
9171 int_pending = TRUE;
9172 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
9173 if (AscIsrChipHalted(asc_dvc) == ERR) {
9174 goto ISR_REPORT_QDONE_FATAL_ERROR;
9175 } else {
9176 saved_ctrl_reg &= (uchar)(~CC_HALT);
9177 }
9178 } else {
9179 ISR_REPORT_QDONE_FATAL_ERROR:
9180 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
9181 while (((status =
9182 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
9183 }
9184 } else {
9185 do {
9186 if ((status =
9187 AscIsrQDone(asc_dvc)) == 1) {
9188 break;
9189 }
9190 } while (status == 0x11);
9191 }
9192 if ((status & 0x80) != 0)
9193 int_pending = ERR;
9194 }
9195 }
9196 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
9197 AscSetChipLramAddr(iop_base, saved_ram_addr);
9198 AscSetChipControl(iop_base, saved_ctrl_reg);
9199 asc_dvc->is_in_int = FALSE;
9200 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009201}
9202
9203/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009204static uchar _asc_mcode_buf[] = {
9205 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9206 0x00, 0x00, 0x00, 0x00,
9207 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
9208 0x00, 0x00, 0x00, 0x00,
9209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9210 0x00, 0x00, 0x00, 0x00,
9211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9212 0x00, 0x00, 0x00, 0x00,
9213 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
9214 0x00, 0xFF, 0x00, 0x00,
9215 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
9216 0x00, 0x00, 0x00, 0x00,
9217 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
9218 0x00, 0x00, 0x00, 0x00,
9219 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
9220 0x00, 0x00, 0x00, 0x00,
9221 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
9222 0x03, 0x23, 0x36, 0x40,
9223 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
9224 0xC2, 0x00, 0x92, 0x80,
9225 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
9226 0xB6, 0x00, 0x92, 0x80,
9227 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
9228 0x92, 0x80, 0x80, 0x62,
9229 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
9230 0xCD, 0x04, 0x4D, 0x00,
9231 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
9232 0xE6, 0x84, 0xD2, 0xC1,
9233 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
9234 0xC6, 0x81, 0xC2, 0x88,
9235 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
9236 0x84, 0x97, 0x07, 0xA6,
9237 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
9238 0xC2, 0x88, 0xCE, 0x00,
9239 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
9240 0x80, 0x63, 0x07, 0xA6,
9241 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
9242 0x34, 0x01, 0x00, 0x33,
9243 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
9244 0x68, 0x98, 0x4D, 0x04,
9245 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
9246 0xF8, 0x88, 0xFB, 0x23,
9247 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
9248 0x00, 0x33, 0x0A, 0x00,
9249 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
9250 0xC2, 0x88, 0xCD, 0x04,
9251 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
9252 0x06, 0xAB, 0x82, 0x01,
9253 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
9254 0x3C, 0x01, 0x00, 0x05,
9255 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
9256 0x15, 0x23, 0xA1, 0x01,
9257 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
9258 0x06, 0x61, 0x00, 0xA0,
9259 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
9260 0xC2, 0x88, 0x06, 0x23,
9261 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
9262 0x57, 0x60, 0x00, 0xA0,
9263 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
9264 0x4B, 0x00, 0x06, 0x61,
9265 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
9266 0x4F, 0x00, 0x84, 0x97,
9267 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
9268 0x48, 0x04, 0x84, 0x80,
9269 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
9270 0x81, 0x73, 0x06, 0x29,
9271 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
9272 0x04, 0x98, 0xF0, 0x80,
9273 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
9274 0x34, 0x02, 0x03, 0xA6,
9275 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
9276 0x46, 0x82, 0xFE, 0x95,
9277 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
9278 0x07, 0xA6, 0x5A, 0x02,
9279 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
9280 0x48, 0x82, 0x60, 0x96,
9281 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
9282 0x04, 0x01, 0x0C, 0xDC,
9283 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
9284 0x6F, 0x00, 0xA5, 0x01,
9285 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
9286 0x02, 0xA6, 0xAA, 0x02,
9287 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
9288 0x01, 0xA6, 0xB4, 0x02,
9289 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
9290 0x80, 0x63, 0x00, 0x43,
9291 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
9292 0x04, 0x61, 0x84, 0x01,
9293 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
9294 0x00, 0x00, 0xEA, 0x82,
9295 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
9296 0x00, 0x33, 0x1F, 0x00,
9297 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
9298 0xB6, 0x2D, 0x01, 0xA6,
9299 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
9300 0x10, 0x03, 0x03, 0xA6,
9301 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
9302 0x7C, 0x95, 0xEE, 0x82,
9303 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
9304 0x04, 0x01, 0x2D, 0xC8,
9305 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
9306 0x05, 0x05, 0x86, 0x98,
9307 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
9308 0x3C, 0x04, 0x06, 0xA6,
9309 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
9310 0x7C, 0x95, 0x32, 0x83,
9311 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
9312 0xEB, 0x04, 0x00, 0x33,
9313 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
9314 0xFF, 0xA2, 0x7A, 0x03,
9315 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
9316 0x00, 0xA2, 0x9A, 0x03,
9317 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
9318 0x01, 0xA6, 0x96, 0x03,
9319 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
9320 0xA4, 0x03, 0x00, 0xA6,
9321 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
9322 0x07, 0xA6, 0xB2, 0x03,
9323 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
9324 0xA8, 0x98, 0x80, 0x42,
9325 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
9326 0xC0, 0x83, 0x00, 0x33,
9327 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
9328 0xA0, 0x01, 0x12, 0x23,
9329 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
9330 0x80, 0x67, 0x05, 0x23,
9331 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
9332 0x06, 0xA6, 0x0A, 0x04,
9333 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
9334 0xF4, 0x83, 0x20, 0x84,
9335 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
9336 0x83, 0x03, 0x80, 0x63,
9337 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
9338 0x38, 0x04, 0x00, 0x33,
9339 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
9340 0x1D, 0x01, 0x06, 0xCC,
9341 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
9342 0xA2, 0x0D, 0x80, 0x63,
9343 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
9344 0x80, 0x63, 0xA3, 0x01,
9345 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
9346 0x76, 0x04, 0xE0, 0x00,
9347 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
9348 0x00, 0x33, 0x1E, 0x00,
9349 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
9350 0x08, 0x23, 0x22, 0xA3,
9351 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
9352 0xC4, 0x04, 0x42, 0x23,
9353 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
9354 0xF8, 0x88, 0x04, 0x98,
9355 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
9356 0x81, 0x62, 0xE8, 0x81,
9357 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
9358 0x00, 0x33, 0x00, 0x81,
9359 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
9360 0xF8, 0x88, 0x04, 0x23,
9361 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
9362 0xF4, 0x04, 0x00, 0x33,
9363 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9364 0x04, 0x23, 0xA0, 0x01,
9365 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9366 0x00, 0xA3, 0x22, 0x05,
9367 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9368 0x46, 0x97, 0xCD, 0x04,
9369 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9370 0x82, 0x01, 0x34, 0x85,
9371 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9372 0x1D, 0x01, 0x04, 0xD6,
9373 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9374 0x49, 0x00, 0x81, 0x01,
9375 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9376 0x49, 0x04, 0x80, 0x01,
9377 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9378 0x01, 0x23, 0xEA, 0x00,
9379 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9380 0x07, 0xA4, 0xF8, 0x05,
9381 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9382 0xC2, 0x88, 0x04, 0xA0,
9383 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9384 0x00, 0xA2, 0xA4, 0x05,
9385 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9386 0x62, 0x97, 0x04, 0x85,
9387 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9388 0xF4, 0x85, 0x03, 0xA0,
9389 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9390 0xCC, 0x86, 0x07, 0xA0,
9391 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9392 0x80, 0x67, 0x80, 0x63,
9393 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9394 0xF8, 0x88, 0x07, 0x23,
9395 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9396 0x00, 0x63, 0x4A, 0x00,
9397 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9398 0x07, 0x41, 0x83, 0x03,
9399 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9400 0x1D, 0x01, 0x01, 0xD6,
9401 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9402 0x07, 0xA6, 0x7C, 0x05,
9403 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9404 0x52, 0x00, 0x06, 0x61,
9405 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9406 0x00, 0x63, 0x1D, 0x01,
9407 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9408 0x07, 0x41, 0x00, 0x63,
9409 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9410 0xDF, 0x00, 0x06, 0xA6,
9411 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9412 0x00, 0x40, 0xC0, 0x20,
9413 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9414 0x06, 0xA6, 0x94, 0x06,
9415 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9416 0x40, 0x0E, 0x80, 0x63,
9417 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9418 0x80, 0x63, 0x00, 0x43,
9419 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9420 0x80, 0x67, 0x40, 0x0E,
9421 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9422 0x07, 0xA6, 0xD6, 0x06,
9423 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9424 0x0A, 0x2B, 0x07, 0xA6,
9425 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9426 0xF4, 0x06, 0xC0, 0x0E,
9427 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9428 0x81, 0x62, 0x04, 0x01,
9429 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9430 0x8C, 0x06, 0x00, 0x33,
9431 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9432 0x80, 0x63, 0x06, 0xA6,
9433 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9434 0x00, 0x00, 0x80, 0x67,
9435 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9436 0xBF, 0x23, 0x04, 0x61,
9437 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9438 0x00, 0x01, 0xF2, 0x00,
9439 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9440 0x80, 0x05, 0x81, 0x05,
9441 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9442 0x70, 0x00, 0x81, 0x01,
9443 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9444 0x70, 0x00, 0x80, 0x01,
9445 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9446 0xF1, 0x00, 0x70, 0x00,
9447 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9448 0x71, 0x04, 0x70, 0x00,
9449 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9450 0xA3, 0x01, 0xA2, 0x01,
9451 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9452 0xC4, 0x07, 0x00, 0x33,
9453 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9454 0x48, 0x00, 0xB0, 0x01,
9455 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9456 0x00, 0xA2, 0xE4, 0x07,
9457 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9458 0x05, 0x05, 0x00, 0x63,
9459 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9460 0x76, 0x08, 0x80, 0x02,
9461 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9462 0x00, 0x02, 0x00, 0xA0,
9463 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9464 0x00, 0x63, 0xF3, 0x04,
9465 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9466 0x00, 0xA2, 0x44, 0x08,
9467 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9468 0x24, 0x08, 0x04, 0x98,
9469 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9470 0x5A, 0x88, 0x02, 0x01,
9471 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9472 0x00, 0xA3, 0x64, 0x08,
9473 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9474 0x06, 0xA6, 0x76, 0x08,
9475 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9476 0x00, 0x63, 0x38, 0x2B,
9477 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9478 0x05, 0x05, 0xB2, 0x09,
9479 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9480 0x80, 0x32, 0x80, 0x36,
9481 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9482 0x40, 0x36, 0x40, 0x3A,
9483 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9484 0x5D, 0x00, 0xFE, 0xC3,
9485 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9486 0xFF, 0xFD, 0x80, 0x73,
9487 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9488 0xA1, 0x23, 0xA1, 0x01,
9489 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9490 0x80, 0x00, 0x03, 0xC2,
9491 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9492 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009493};
9494
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009495static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9496static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009497
9498#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009499static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9500 INQUIRY,
9501 REQUEST_SENSE,
9502 READ_CAPACITY,
9503 READ_TOC,
9504 MODE_SELECT,
9505 MODE_SENSE,
9506 MODE_SELECT_10,
9507 MODE_SENSE_10,
9508 0xFF,
9509 0xFF,
9510 0xFF,
9511 0xFF,
9512 0xFF,
9513 0xFF,
9514 0xFF,
9515 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009516};
9517
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009518static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009519{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009520 PortAddr iop_base;
9521 ulong last_int_level;
9522 int sta;
9523 int n_q_required;
9524 int disable_syn_offset_one_fix;
9525 int i;
9526 ASC_PADDR addr;
9527 ASC_EXE_CALLBACK asc_exe_callback;
9528 ushort sg_entry_cnt = 0;
9529 ushort sg_entry_cnt_minus_one = 0;
9530 uchar target_ix;
9531 uchar tid_no;
9532 uchar sdtr_data;
9533 uchar extra_bytes;
9534 uchar scsi_cmd;
9535 uchar disable_cmd;
9536 ASC_SG_HEAD *sg_head;
9537 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009538
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009539 iop_base = asc_dvc->iop_base;
9540 sg_head = scsiq->sg_head;
9541 asc_exe_callback = asc_dvc->exe_callback;
9542 if (asc_dvc->err_code != 0)
9543 return (ERR);
9544 if (scsiq == (ASC_SCSI_Q *)0L) {
9545 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9546 return (ERR);
9547 }
9548 scsiq->q1.q_no = 0;
9549 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9550 scsiq->q1.extra_bytes = 0;
9551 }
9552 sta = 0;
9553 target_ix = scsiq->q2.target_ix;
9554 tid_no = ASC_TIX_TO_TID(target_ix);
9555 n_q_required = 1;
9556 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9557 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9558 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9559 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9560 AscMsgOutSDTR(asc_dvc,
9561 asc_dvc->
9562 sdtr_period_tbl[(sdtr_data >> 4) &
9563 (uchar)(asc_dvc->
9564 max_sdtr_index -
9565 1)],
9566 (uchar)(sdtr_data & (uchar)
9567 ASC_SYN_MAX_OFFSET));
9568 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9569 }
9570 }
9571 last_int_level = DvcEnterCritical();
9572 if (asc_dvc->in_critical_cnt != 0) {
9573 DvcLeaveCritical(last_int_level);
9574 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9575 return (ERR);
9576 }
9577 asc_dvc->in_critical_cnt++;
9578 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9579 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9580 asc_dvc->in_critical_cnt--;
9581 DvcLeaveCritical(last_int_level);
9582 return (ERR);
9583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009584#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009585 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9586 asc_dvc->in_critical_cnt--;
9587 DvcLeaveCritical(last_int_level);
9588 return (ERR);
9589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009590#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009591 if (sg_entry_cnt == 1) {
9592 scsiq->q1.data_addr =
9593 (ADV_PADDR)sg_head->sg_list[0].addr;
9594 scsiq->q1.data_cnt =
9595 (ADV_DCNT)sg_head->sg_list[0].bytes;
9596 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9597 }
9598 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9599 }
9600 scsi_cmd = scsiq->cdbptr[0];
9601 disable_syn_offset_one_fix = FALSE;
9602 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9603 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9604 if (scsiq->q1.cntl & QC_SG_HEAD) {
9605 data_cnt = 0;
9606 for (i = 0; i < sg_entry_cnt; i++) {
9607 data_cnt +=
9608 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9609 bytes);
9610 }
9611 } else {
9612 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9613 }
9614 if (data_cnt != 0UL) {
9615 if (data_cnt < 512UL) {
9616 disable_syn_offset_one_fix = TRUE;
9617 } else {
9618 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9619 i++) {
9620 disable_cmd =
9621 _syn_offset_one_disable_cmd[i];
9622 if (disable_cmd == 0xFF) {
9623 break;
9624 }
9625 if (scsi_cmd == disable_cmd) {
9626 disable_syn_offset_one_fix =
9627 TRUE;
9628 break;
9629 }
9630 }
9631 }
9632 }
9633 }
9634 if (disable_syn_offset_one_fix) {
9635 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9636 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9637 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9638 } else {
9639 scsiq->q2.tag_code &= 0x27;
9640 }
9641 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9642 if (asc_dvc->bug_fix_cntl) {
9643 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9644 if ((scsi_cmd == READ_6) ||
9645 (scsi_cmd == READ_10)) {
9646 addr =
9647 (ADV_PADDR)le32_to_cpu(sg_head->
9648 sg_list
9649 [sg_entry_cnt_minus_one].
9650 addr) +
9651 (ADV_DCNT)le32_to_cpu(sg_head->
9652 sg_list
9653 [sg_entry_cnt_minus_one].
9654 bytes);
9655 extra_bytes =
9656 (uchar)((ushort)addr & 0x0003);
9657 if ((extra_bytes != 0)
9658 &&
9659 ((scsiq->q2.
9660 tag_code &
9661 ASC_TAG_FLAG_EXTRA_BYTES)
9662 == 0)) {
9663 scsiq->q2.tag_code |=
9664 ASC_TAG_FLAG_EXTRA_BYTES;
9665 scsiq->q1.extra_bytes =
9666 extra_bytes;
9667 data_cnt =
9668 le32_to_cpu(sg_head->
9669 sg_list
9670 [sg_entry_cnt_minus_one].
9671 bytes);
9672 data_cnt -=
9673 (ASC_DCNT) extra_bytes;
9674 sg_head->
9675 sg_list
9676 [sg_entry_cnt_minus_one].
9677 bytes =
9678 cpu_to_le32(data_cnt);
9679 }
9680 }
9681 }
9682 }
9683 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009684#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009685 /*
9686 * Set the sg_entry_cnt to the maximum possible. The rest of
9687 * the SG elements will be copied when the RISC completes the
9688 * SG elements that fit and halts.
9689 */
9690 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9691 sg_entry_cnt = ASC_MAX_SG_LIST;
9692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009693#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009694 n_q_required = AscSgListToQueue(sg_entry_cnt);
9695 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9696 (uint) n_q_required)
9697 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9698 if ((sta =
9699 AscSendScsiQueue(asc_dvc, scsiq,
9700 n_q_required)) == 1) {
9701 asc_dvc->in_critical_cnt--;
9702 if (asc_exe_callback != 0) {
9703 (*asc_exe_callback) (asc_dvc, scsiq);
9704 }
9705 DvcLeaveCritical(last_int_level);
9706 return (sta);
9707 }
9708 }
9709 } else {
9710 if (asc_dvc->bug_fix_cntl) {
9711 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9712 if ((scsi_cmd == READ_6) ||
9713 (scsi_cmd == READ_10)) {
9714 addr =
9715 le32_to_cpu(scsiq->q1.data_addr) +
9716 le32_to_cpu(scsiq->q1.data_cnt);
9717 extra_bytes =
9718 (uchar)((ushort)addr & 0x0003);
9719 if ((extra_bytes != 0)
9720 &&
9721 ((scsiq->q2.
9722 tag_code &
9723 ASC_TAG_FLAG_EXTRA_BYTES)
9724 == 0)) {
9725 data_cnt =
9726 le32_to_cpu(scsiq->q1.
9727 data_cnt);
9728 if (((ushort)data_cnt & 0x01FF)
9729 == 0) {
9730 scsiq->q2.tag_code |=
9731 ASC_TAG_FLAG_EXTRA_BYTES;
9732 data_cnt -= (ASC_DCNT)
9733 extra_bytes;
9734 scsiq->q1.data_cnt =
9735 cpu_to_le32
9736 (data_cnt);
9737 scsiq->q1.extra_bytes =
9738 extra_bytes;
9739 }
9740 }
9741 }
9742 }
9743 }
9744 n_q_required = 1;
9745 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9746 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9747 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9748 n_q_required)) == 1) {
9749 asc_dvc->in_critical_cnt--;
9750 if (asc_exe_callback != 0) {
9751 (*asc_exe_callback) (asc_dvc, scsiq);
9752 }
9753 DvcLeaveCritical(last_int_level);
9754 return (sta);
9755 }
9756 }
9757 }
9758 asc_dvc->in_critical_cnt--;
9759 DvcLeaveCritical(last_int_level);
9760 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009761}
9762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009763static int
9764AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009765{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009766 PortAddr iop_base;
9767 uchar free_q_head;
9768 uchar next_qp;
9769 uchar tid_no;
9770 uchar target_ix;
9771 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009772
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009773 iop_base = asc_dvc->iop_base;
9774 target_ix = scsiq->q2.target_ix;
9775 tid_no = ASC_TIX_TO_TID(target_ix);
9776 sta = 0;
9777 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9778 if (n_q_required > 1) {
9779 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9780 free_q_head, (uchar)
9781 (n_q_required)))
9782 != (uchar)ASC_QLINK_END) {
9783 asc_dvc->last_q_shortage = 0;
9784 scsiq->sg_head->queue_cnt = n_q_required - 1;
9785 scsiq->q1.q_no = free_q_head;
9786 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9787 free_q_head)) == 1) {
9788 AscPutVarFreeQHead(iop_base, next_qp);
9789 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9790 asc_dvc->cur_dvc_qng[tid_no]++;
9791 }
9792 return (sta);
9793 }
9794 } else if (n_q_required == 1) {
9795 if ((next_qp = AscAllocFreeQueue(iop_base,
9796 free_q_head)) !=
9797 ASC_QLINK_END) {
9798 scsiq->q1.q_no = free_q_head;
9799 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9800 free_q_head)) == 1) {
9801 AscPutVarFreeQHead(iop_base, next_qp);
9802 asc_dvc->cur_total_qng++;
9803 asc_dvc->cur_dvc_qng[tid_no]++;
9804 }
9805 return (sta);
9806 }
9807 }
9808 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009809}
9810
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009811static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009812{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009813 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009814
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009815 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9816 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9817 n_sg_list_qs++;
9818 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009819}
9820
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009821static uint
9822AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009823{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009824 uint cur_used_qs;
9825 uint cur_free_qs;
9826 ASC_SCSI_BIT_ID_TYPE target_id;
9827 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009829 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9830 tid_no = ASC_TIX_TO_TID(target_ix);
9831 if ((asc_dvc->unit_not_ready & target_id) ||
9832 (asc_dvc->queue_full_or_busy & target_id)) {
9833 return (0);
9834 }
9835 if (n_qs == 1) {
9836 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9837 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9838 } else {
9839 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9840 (uint) ASC_MIN_FREE_Q;
9841 }
9842 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9843 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9844 if (asc_dvc->cur_dvc_qng[tid_no] >=
9845 asc_dvc->max_dvc_qng[tid_no]) {
9846 return (0);
9847 }
9848 return (cur_free_qs);
9849 }
9850 if (n_qs > 1) {
9851 if ((n_qs > asc_dvc->last_q_shortage)
9852 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9853 asc_dvc->last_q_shortage = n_qs;
9854 }
9855 }
9856 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009857}
9858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009859static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009860{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009861 ushort q_addr;
9862 uchar tid_no;
9863 uchar sdtr_data;
9864 uchar syn_period_ix;
9865 uchar syn_offset;
9866 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009867
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009868 iop_base = asc_dvc->iop_base;
9869 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9870 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9871 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9872 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9873 syn_period_ix =
9874 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9875 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9876 AscMsgOutSDTR(asc_dvc,
9877 asc_dvc->sdtr_period_tbl[syn_period_ix],
9878 syn_offset);
9879 scsiq->q1.cntl |= QC_MSG_OUT;
9880 }
9881 q_addr = ASC_QNO_TO_QADDR(q_no);
9882 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9883 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9884 }
9885 scsiq->q1.status = QS_FREE;
9886 AscMemWordCopyPtrToLram(iop_base,
9887 q_addr + ASC_SCSIQ_CDB_BEG,
9888 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009889
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009890 DvcPutScsiQ(iop_base,
9891 q_addr + ASC_SCSIQ_CPY_BEG,
9892 (uchar *)&scsiq->q1.cntl,
9893 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9894 AscWriteLramWord(iop_base,
9895 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9896 (ushort)(((ushort)scsiq->q1.
9897 q_no << 8) | (ushort)QS_READY));
9898 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009899}
9900
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009901static int
9902AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009903{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009904 int sta;
9905 int i;
9906 ASC_SG_HEAD *sg_head;
9907 ASC_SG_LIST_Q scsi_sg_q;
9908 ASC_DCNT saved_data_addr;
9909 ASC_DCNT saved_data_cnt;
9910 PortAddr iop_base;
9911 ushort sg_list_dwords;
9912 ushort sg_index;
9913 ushort sg_entry_cnt;
9914 ushort q_addr;
9915 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009916
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009917 iop_base = asc_dvc->iop_base;
9918 sg_head = scsiq->sg_head;
9919 saved_data_addr = scsiq->q1.data_addr;
9920 saved_data_cnt = scsiq->q1.data_cnt;
9921 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9922 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009923#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009924 /*
9925 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9926 * then not all SG elements will fit in the allocated queues.
9927 * The rest of the SG elements will be copied when the RISC
9928 * completes the SG elements that fit and halts.
9929 */
9930 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9931 /*
9932 * Set sg_entry_cnt to be the number of SG elements that
9933 * will fit in the allocated SG queues. It is minus 1, because
9934 * the first SG element is handled above. ASC_MAX_SG_LIST is
9935 * already inflated by 1 to account for this. For example it
9936 * may be 50 which is 1 + 7 queues * 7 SG elements.
9937 */
9938 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009940 /*
9941 * Keep track of remaining number of SG elements that will
9942 * need to be handled from a_isr.c.
9943 */
9944 scsiq->remain_sg_entry_cnt =
9945 sg_head->entry_cnt - ASC_MAX_SG_LIST;
9946 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009947#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009948 /*
9949 * Set sg_entry_cnt to be the number of SG elements that
9950 * will fit in the allocated SG queues. It is minus 1, because
9951 * the first SG element is handled above.
9952 */
9953 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009954#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009956#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009957 if (sg_entry_cnt != 0) {
9958 scsiq->q1.cntl |= QC_SG_HEAD;
9959 q_addr = ASC_QNO_TO_QADDR(q_no);
9960 sg_index = 1;
9961 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
9962 scsi_sg_q.sg_head_qp = q_no;
9963 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
9964 for (i = 0; i < sg_head->queue_cnt; i++) {
9965 scsi_sg_q.seq_no = i + 1;
9966 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
9967 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
9968 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
9969 if (i == 0) {
9970 scsi_sg_q.sg_list_cnt =
9971 ASC_SG_LIST_PER_Q;
9972 scsi_sg_q.sg_cur_list_cnt =
9973 ASC_SG_LIST_PER_Q;
9974 } else {
9975 scsi_sg_q.sg_list_cnt =
9976 ASC_SG_LIST_PER_Q - 1;
9977 scsi_sg_q.sg_cur_list_cnt =
9978 ASC_SG_LIST_PER_Q - 1;
9979 }
9980 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009981#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009982 /*
9983 * This is the last SG queue in the list of
9984 * allocated SG queues. If there are more
9985 * SG elements than will fit in the allocated
9986 * queues, then set the QCSG_SG_XFER_MORE flag.
9987 */
9988 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9989 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
9990 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009991#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009992 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009993#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009994 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009995#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009996 sg_list_dwords = sg_entry_cnt << 1;
9997 if (i == 0) {
9998 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
9999 scsi_sg_q.sg_cur_list_cnt =
10000 sg_entry_cnt;
10001 } else {
10002 scsi_sg_q.sg_list_cnt =
10003 sg_entry_cnt - 1;
10004 scsi_sg_q.sg_cur_list_cnt =
10005 sg_entry_cnt - 1;
10006 }
10007 sg_entry_cnt = 0;
10008 }
10009 next_qp = AscReadLramByte(iop_base,
10010 (ushort)(q_addr +
10011 ASC_SCSIQ_B_FWD));
10012 scsi_sg_q.q_no = next_qp;
10013 q_addr = ASC_QNO_TO_QADDR(next_qp);
10014 AscMemWordCopyPtrToLram(iop_base,
10015 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
10016 (uchar *)&scsi_sg_q,
10017 sizeof(ASC_SG_LIST_Q) >> 1);
10018 AscMemDWordCopyPtrToLram(iop_base,
10019 q_addr + ASC_SGQ_LIST_BEG,
10020 (uchar *)&sg_head->
10021 sg_list[sg_index],
10022 sg_list_dwords);
10023 sg_index += ASC_SG_LIST_PER_Q;
10024 scsiq->next_sg_index = sg_index;
10025 }
10026 } else {
10027 scsiq->q1.cntl &= ~QC_SG_HEAD;
10028 }
10029 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
10030 scsiq->q1.data_addr = saved_data_addr;
10031 scsiq->q1.data_cnt = saved_data_cnt;
10032 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010033}
10034
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010035static int
10036AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010037{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010038 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010039
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010040 if (AscHostReqRiscHalt(iop_base)) {
10041 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
10042 AscStartChip(iop_base);
10043 return (sta);
10044 }
10045 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010046}
10047
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010048static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010049{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010050 ASC_SCSI_BIT_ID_TYPE org_id;
10051 int i;
10052 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010053
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010054 AscSetBank(iop_base, 1);
10055 org_id = AscReadChipDvcID(iop_base);
10056 for (i = 0; i <= ASC_MAX_TID; i++) {
10057 if (org_id == (0x01 << i))
10058 break;
10059 }
10060 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
10061 AscWriteChipDvcID(iop_base, id);
10062 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
10063 AscSetBank(iop_base, 0);
10064 AscSetChipSyn(iop_base, sdtr_data);
10065 if (AscGetChipSyn(iop_base) != sdtr_data) {
10066 sta = FALSE;
10067 }
10068 } else {
10069 sta = FALSE;
10070 }
10071 AscSetBank(iop_base, 1);
10072 AscWriteChipDvcID(iop_base, org_id);
10073 AscSetBank(iop_base, 0);
10074 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010075}
10076
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010077static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010078{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010079 uchar i;
10080 ushort s_addr;
10081 PortAddr iop_base;
10082 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010083
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010084 iop_base = asc_dvc->iop_base;
10085 warn_code = 0;
10086 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
10087 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
10088 64) >> 1)
10089 );
10090 i = ASC_MIN_ACTIVE_QNO;
10091 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
10092 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10093 (uchar)(i + 1));
10094 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10095 (uchar)(asc_dvc->max_total_qng));
10096 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10097 (uchar)i);
10098 i++;
10099 s_addr += ASC_QBLK_SIZE;
10100 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
10101 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10102 (uchar)(i + 1));
10103 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10104 (uchar)(i - 1));
10105 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10106 (uchar)i);
10107 }
10108 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10109 (uchar)ASC_QLINK_END);
10110 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10111 (uchar)(asc_dvc->max_total_qng - 1));
10112 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10113 (uchar)asc_dvc->max_total_qng);
10114 i++;
10115 s_addr += ASC_QBLK_SIZE;
10116 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
10117 i++, s_addr += ASC_QBLK_SIZE) {
10118 AscWriteLramByte(iop_base,
10119 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
10120 AscWriteLramByte(iop_base,
10121 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
10122 AscWriteLramByte(iop_base,
10123 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
10124 }
10125 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010126}
10127
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010128static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010129{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010130 PortAddr iop_base;
10131 int i;
10132 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010133
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010134 iop_base = asc_dvc->iop_base;
10135 AscPutRiscVarFreeQHead(iop_base, 1);
10136 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
10137 AscPutVarFreeQHead(iop_base, 1);
10138 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
10139 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
10140 (uchar)((int)asc_dvc->max_total_qng + 1));
10141 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
10142 (uchar)((int)asc_dvc->max_total_qng + 2));
10143 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
10144 asc_dvc->max_total_qng);
10145 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
10146 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
10147 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
10148 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
10149 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
10150 AscPutQDoneInProgress(iop_base, 0);
10151 lram_addr = ASC_QADR_BEG;
10152 for (i = 0; i < 32; i++, lram_addr += 2) {
10153 AscWriteLramWord(iop_base, lram_addr, 0);
10154 }
10155 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010156}
10157
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010158static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010159{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010160 if (asc_dvc->err_code == 0) {
10161 asc_dvc->err_code = err_code;
10162 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
10163 err_code);
10164 }
10165 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010166}
10167
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010168static uchar
10169AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010170{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010171 EXT_MSG sdtr_buf;
10172 uchar sdtr_period_index;
10173 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010174
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010175 iop_base = asc_dvc->iop_base;
10176 sdtr_buf.msg_type = MS_EXTEND;
10177 sdtr_buf.msg_len = MS_SDTR_LEN;
10178 sdtr_buf.msg_req = MS_SDTR_CODE;
10179 sdtr_buf.xfer_period = sdtr_period;
10180 sdtr_offset &= ASC_SYN_MAX_OFFSET;
10181 sdtr_buf.req_ack_offset = sdtr_offset;
10182 if ((sdtr_period_index =
10183 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
10184 asc_dvc->max_sdtr_index) {
10185 AscMemWordCopyPtrToLram(iop_base,
10186 ASCV_MSGOUT_BEG,
10187 (uchar *)&sdtr_buf,
10188 sizeof(EXT_MSG) >> 1);
10189 return ((sdtr_period_index << 4) | sdtr_offset);
10190 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010191
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010192 sdtr_buf.req_ack_offset = 0;
10193 AscMemWordCopyPtrToLram(iop_base,
10194 ASCV_MSGOUT_BEG,
10195 (uchar *)&sdtr_buf,
10196 sizeof(EXT_MSG) >> 1);
10197 return (0);
10198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010199}
10200
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010201static uchar
10202AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010203{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010204 uchar byte;
10205 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010206
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010207 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
10208 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
10209 ) {
10210 return (0xFF);
10211 }
10212 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
10213 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010214}
10215
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010216static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010217{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010218 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
10219 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
10220 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010221}
10222
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010223static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010224{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010225 uchar *period_table;
10226 int max_index;
10227 int min_index;
10228 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010229
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010230 period_table = asc_dvc->sdtr_period_tbl;
10231 max_index = (int)asc_dvc->max_sdtr_index;
10232 min_index = (int)asc_dvc->host_init_sdtr_index;
10233 if ((syn_time <= period_table[max_index])) {
10234 for (i = min_index; i < (max_index - 1); i++) {
10235 if (syn_time <= period_table[i]) {
10236 return ((uchar)i);
10237 }
10238 }
10239 return ((uchar)max_index);
10240 } else {
10241 return ((uchar)(max_index + 1));
10242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010243}
10244
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010245static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010246{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010247 ushort q_addr;
10248 uchar next_qp;
10249 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010250
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010251 q_addr = ASC_QNO_TO_QADDR(free_q_head);
10252 q_status = (uchar)AscReadLramByte(iop_base,
10253 (ushort)(q_addr +
10254 ASC_SCSIQ_B_STATUS));
10255 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
10256 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
10257 return (next_qp);
10258 }
10259 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010260}
10261
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010262static uchar
10263AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010264{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010265 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010266
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010267 for (i = 0; i < n_free_q; i++) {
10268 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
10269 == ASC_QLINK_END) {
10270 return (ASC_QLINK_END);
10271 }
10272 }
10273 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010274}
10275
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010276static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010277{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010278 int count = 0;
10279 int sta = 0;
10280 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010281
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010282 if (AscIsChipHalted(iop_base))
10283 return (1);
10284 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
10285 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10286 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
10287 do {
10288 if (AscIsChipHalted(iop_base)) {
10289 sta = 1;
10290 break;
10291 }
10292 DvcSleepMilliSecond(100);
10293 } while (count++ < 20);
10294 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
10295 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010296}
10297
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010298static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010299{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010300 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010301
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010302 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
10303 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10304 ASC_STOP_REQ_RISC_STOP);
10305 do {
10306 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
10307 ASC_STOP_ACK_RISC_STOP) {
10308 return (1);
10309 }
10310 DvcSleepMilliSecond(100);
10311 } while (count++ < 20);
10312 }
10313 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010314}
10315
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010316static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010317{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010318 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010319}
10320
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010321static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010322{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010323 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010324}
10325
10326#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010327static ASC_DCNT __init AscGetEisaProductID(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010328{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010329 PortAddr eisa_iop;
10330 ushort product_id_high, product_id_low;
10331 ASC_DCNT product_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010332
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010333 eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
10334 product_id_low = inpw(eisa_iop);
10335 product_id_high = inpw(eisa_iop + 2);
10336 product_id = ((ASC_DCNT) product_id_high << 16) |
10337 (ASC_DCNT) product_id_low;
10338 return (product_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010339}
10340
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010341static PortAddr __init AscSearchIOPortAddrEISA(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010342{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010343 ASC_DCNT eisa_product_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010344
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010345 if (iop_base == 0) {
10346 iop_base = ASC_EISA_MIN_IOP_ADDR;
10347 } else {
10348 if (iop_base == ASC_EISA_MAX_IOP_ADDR)
10349 return (0);
10350 if ((iop_base & 0x0050) == 0x0050) {
10351 iop_base += ASC_EISA_BIG_IOP_GAP;
10352 } else {
10353 iop_base += ASC_EISA_SMALL_IOP_GAP;
10354 }
10355 }
10356 while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
10357 eisa_product_id = AscGetEisaProductID(iop_base);
10358 if ((eisa_product_id == ASC_EISA_ID_740) ||
10359 (eisa_product_id == ASC_EISA_ID_750)) {
10360 if (AscFindSignature(iop_base)) {
10361 inpw(iop_base + 4);
10362 return (iop_base);
10363 }
10364 }
10365 if (iop_base == ASC_EISA_MAX_IOP_ADDR)
10366 return (0);
10367 if ((iop_base & 0x0050) == 0x0050) {
10368 iop_base += ASC_EISA_BIG_IOP_GAP;
10369 } else {
10370 iop_base += ASC_EISA_SMALL_IOP_GAP;
10371 }
10372 }
10373 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010374}
10375#endif /* CONFIG_ISA */
10376
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010377static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010378{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010379 AscSetChipControl(iop_base, 0);
10380 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10381 return (0);
10382 }
10383 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010384}
10385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010386static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010387{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010388 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010389
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010390 cc_val =
10391 AscGetChipControl(iop_base) &
10392 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
10393 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
10394 AscSetChipIH(iop_base, INS_HALT);
10395 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10396 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
10397 return (0);
10398 }
10399 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010400}
10401
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010402static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010403{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010404 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10405 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
10406 return (1);
10407 }
10408 }
10409 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010410}
10411
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010412static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010413{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010414 AscSetBank(iop_base, 1);
10415 AscWriteChipIH(iop_base, ins_code);
10416 AscSetBank(iop_base, 0);
10417 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010418}
10419
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010420static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010421{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010422 uchar host_flag;
10423 uchar risc_flag;
10424 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010425
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010426 loop = 0;
10427 do {
10428 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10429 if (loop++ > 0x7FFF) {
10430 break;
10431 }
10432 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10433 host_flag =
10434 AscReadLramByte(iop_base,
10435 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10436 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10437 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10438 AscSetChipStatus(iop_base, CIW_INT_ACK);
10439 loop = 0;
10440 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10441 AscSetChipStatus(iop_base, CIW_INT_ACK);
10442 if (loop++ > 3) {
10443 break;
10444 }
10445 }
10446 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10447 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010448}
10449
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010450static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010451{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010452 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010453
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010454 cfg = AscGetChipCfgLsw(iop_base);
10455 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10456 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010457}
10458
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010459static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010460{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010461 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010462
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010463 cfg = AscGetChipCfgLsw(iop_base);
10464 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10465 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010466}
10467
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010468static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010469{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010470 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010471
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010472 val = AscGetChipControl(iop_base) &
10473 (~
10474 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10475 CC_CHIP_RESET));
10476 if (bank == 1) {
10477 val |= CC_BANK_ONE;
10478 } else if (bank == 2) {
10479 val |= CC_DIAG | CC_BANK_ONE;
10480 } else {
10481 val &= ~CC_BANK_ONE;
10482 }
10483 AscSetChipControl(iop_base, val);
10484 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010485}
10486
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010487static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010488{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010489 PortAddr iop_base;
10490 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010491
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010492 iop_base = asc_dvc->iop_base;
10493 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10494 && (i-- > 0)) {
10495 DvcSleepMilliSecond(100);
10496 }
10497 AscStopChip(iop_base);
10498 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10499 DvcDelayNanoSecond(asc_dvc, 60000);
10500 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10501 AscSetChipIH(iop_base, INS_HALT);
10502 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10503 AscSetChipControl(iop_base, CC_HALT);
10504 DvcSleepMilliSecond(200);
10505 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10506 AscSetChipStatus(iop_base, 0);
10507 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010508}
10509
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010510static ASC_DCNT __init AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010511{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010512 if (bus_type & ASC_IS_ISA)
10513 return (ASC_MAX_ISA_DMA_COUNT);
10514 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10515 return (ASC_MAX_VL_DMA_COUNT);
10516 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010517}
10518
10519#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010520static ushort __init AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010521{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010522 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010523
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010524 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10525 if (channel == 0x03)
10526 return (0);
10527 else if (channel == 0x00)
10528 return (7);
10529 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010530}
10531
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010532static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010533{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010534 ushort cfg_lsw;
10535 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010536
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010537 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10538 if (dma_channel == 7)
10539 value = 0x00;
10540 else
10541 value = dma_channel - 4;
10542 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10543 cfg_lsw |= value;
10544 AscSetChipCfgLsw(iop_base, cfg_lsw);
10545 return (AscGetIsaDmaChannel(iop_base));
10546 }
10547 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010548}
10549
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010550static uchar __init AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010551{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010552 speed_value &= 0x07;
10553 AscSetBank(iop_base, 1);
10554 AscWriteChipDmaSpeed(iop_base, speed_value);
10555 AscSetBank(iop_base, 0);
10556 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010557}
10558
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010559static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010560{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010561 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010563 AscSetBank(iop_base, 1);
10564 speed_value = AscReadChipDmaSpeed(iop_base);
10565 speed_value &= 0x07;
10566 AscSetBank(iop_base, 0);
10567 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010568}
10569#endif /* CONFIG_ISA */
10570
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010571static ushort __init
10572AscReadPCIConfigWord(ASC_DVC_VAR *asc_dvc, ushort pci_config_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010573{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010574 uchar lsb, msb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010575
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010576 lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
10577 msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
10578 return ((ushort)((msb << 8) | lsb));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010579}
10580
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010581static ushort __init AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010582{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010583 ushort warn_code;
10584 PortAddr iop_base;
10585 ushort PCIDeviceID;
10586 ushort PCIVendorID;
10587 uchar PCIRevisionID;
10588 uchar prevCmdRegBits;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010589
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010590 warn_code = 0;
10591 iop_base = asc_dvc->iop_base;
10592 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
10593 if (asc_dvc->err_code != 0) {
10594 return (UW_ERR);
10595 }
10596 if (asc_dvc->bus_type == ASC_IS_PCI) {
10597 PCIVendorID = AscReadPCIConfigWord(asc_dvc,
10598 AscPCIConfigVendorIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010599
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010600 PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
10601 AscPCIConfigDeviceIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010602
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010603 PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
10604 AscPCIConfigRevisionIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010605
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010606 if (PCIVendorID != PCI_VENDOR_ID_ASP) {
10607 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10608 }
10609 prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
10610 AscPCIConfigCommandRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010611
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010612 if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
10613 AscPCICmdRegBits_IOMemBusMaster) {
10614 DvcWritePCIConfigByte(asc_dvc,
10615 AscPCIConfigCommandRegister,
10616 (prevCmdRegBits |
10617 AscPCICmdRegBits_IOMemBusMaster));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010618
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010619 if ((DvcReadPCIConfigByte(asc_dvc,
10620 AscPCIConfigCommandRegister)
10621 & AscPCICmdRegBits_IOMemBusMaster)
10622 != AscPCICmdRegBits_IOMemBusMaster) {
10623 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10624 }
10625 }
10626 if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
10627 (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
10628 DvcWritePCIConfigByte(asc_dvc,
10629 AscPCIConfigLatencyTimer, 0x00);
10630 if (DvcReadPCIConfigByte
10631 (asc_dvc, AscPCIConfigLatencyTimer)
10632 != 0x00) {
10633 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10634 }
10635 } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
10636 if (DvcReadPCIConfigByte(asc_dvc,
10637 AscPCIConfigLatencyTimer) <
10638 0x20) {
10639 DvcWritePCIConfigByte(asc_dvc,
10640 AscPCIConfigLatencyTimer,
10641 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010643 if (DvcReadPCIConfigByte(asc_dvc,
10644 AscPCIConfigLatencyTimer)
10645 < 0x20) {
10646 warn_code |=
10647 ASC_WARN_SET_PCI_CONFIG_SPACE;
10648 }
10649 }
10650 }
10651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010653 if (AscFindSignature(iop_base)) {
10654 warn_code |= AscInitAscDvcVar(asc_dvc);
10655 warn_code |= AscInitFromEEP(asc_dvc);
10656 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
10657 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
10658 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
10659 }
10660 } else {
10661 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10662 }
10663 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010664}
10665
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010666static ushort __init AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010667{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010668 ushort warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010669
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010670 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10671 if (asc_dvc->err_code != 0)
10672 return (UW_ERR);
10673 if (AscFindSignature(asc_dvc->iop_base)) {
10674 warn_code |= AscInitFromAscDvcVar(asc_dvc);
10675 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10676 } else {
10677 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10678 }
10679 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010680}
10681
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010682static ushort __init AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010683{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010684 PortAddr iop_base;
10685 ushort cfg_msw;
10686 ushort warn_code;
10687 ushort pci_device_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010688
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010689 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010690#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010691 if (asc_dvc->cfg->dev)
10692 pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010693#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010694 warn_code = 0;
10695 cfg_msw = AscGetChipCfgMsw(iop_base);
10696 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10697 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10698 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10699 AscSetChipCfgMsw(iop_base, cfg_msw);
10700 }
10701 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10702 asc_dvc->cfg->cmd_qng_enabled) {
10703 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10704 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10705 }
10706 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10707 warn_code |= ASC_WARN_AUTO_CONFIG;
10708 }
10709 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10710 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10711 != asc_dvc->irq_no) {
10712 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10713 }
10714 }
10715 if (asc_dvc->bus_type & ASC_IS_PCI) {
10716 cfg_msw &= 0xFFC0;
10717 AscSetChipCfgMsw(iop_base, cfg_msw);
10718 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10719 } else {
10720 if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
10721 (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
10722 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10723 asc_dvc->bug_fix_cntl |=
10724 ASC_BUG_FIX_ASYN_USE_SYN;
10725 }
10726 }
10727 } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
10728 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10729 == ASC_CHIP_VER_ASYN_BUG) {
10730 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10731 }
10732 }
10733 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10734 asc_dvc->cfg->chip_scsi_id) {
10735 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10736 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010737#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010738 if (asc_dvc->bus_type & ASC_IS_ISA) {
10739 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10740 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010742#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010743 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010744}
10745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010746static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010747{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010748 ushort warn_code;
10749 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010750
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010751 iop_base = asc_dvc->iop_base;
10752 warn_code = 0;
10753 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10754 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10755 AscResetChipAndScsiBus(asc_dvc);
10756 DvcSleepMilliSecond((ASC_DCNT)
10757 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10758 }
10759 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10760 if (asc_dvc->err_code != 0)
10761 return (UW_ERR);
10762 if (!AscFindSignature(asc_dvc->iop_base)) {
10763 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10764 return (warn_code);
10765 }
10766 AscDisableInterrupt(iop_base);
10767 warn_code |= AscInitLram(asc_dvc);
10768 if (asc_dvc->err_code != 0)
10769 return (UW_ERR);
10770 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10771 (ulong)_asc_mcode_chksum);
10772 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10773 _asc_mcode_size) != _asc_mcode_chksum) {
10774 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10775 return (warn_code);
10776 }
10777 warn_code |= AscInitMicroCodeVar(asc_dvc);
10778 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10779 AscEnableInterrupt(iop_base);
10780 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010781}
10782
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010783static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010784{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010785 int i;
10786 PortAddr iop_base;
10787 ushort warn_code;
10788 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010789
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010790 iop_base = asc_dvc->iop_base;
10791 warn_code = 0;
10792 asc_dvc->err_code = 0;
10793 if ((asc_dvc->bus_type &
10794 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10795 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10796 }
10797 AscSetChipControl(iop_base, CC_HALT);
10798 AscSetChipStatus(iop_base, 0);
10799 asc_dvc->bug_fix_cntl = 0;
10800 asc_dvc->pci_fix_asyn_xfer = 0;
10801 asc_dvc->pci_fix_asyn_xfer_always = 0;
10802 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10803 asc_dvc->sdtr_done = 0;
10804 asc_dvc->cur_total_qng = 0;
10805 asc_dvc->is_in_int = 0;
10806 asc_dvc->in_critical_cnt = 0;
10807 asc_dvc->last_q_shortage = 0;
10808 asc_dvc->use_tagged_qng = 0;
10809 asc_dvc->no_scam = 0;
10810 asc_dvc->unit_not_ready = 0;
10811 asc_dvc->queue_full_or_busy = 0;
10812 asc_dvc->redo_scam = 0;
10813 asc_dvc->res2 = 0;
10814 asc_dvc->host_init_sdtr_index = 0;
10815 asc_dvc->cfg->can_tagged_qng = 0;
10816 asc_dvc->cfg->cmd_qng_enabled = 0;
10817 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10818 asc_dvc->init_sdtr = 0;
10819 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10820 asc_dvc->scsi_reset_wait = 3;
10821 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10822 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10823 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10824 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10825 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10826 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10827 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10828 ASC_LIB_VERSION_MINOR;
10829 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10830 asc_dvc->cfg->chip_version = chip_version;
10831 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10832 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10833 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10834 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10835 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10836 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10837 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10838 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10839 asc_dvc->max_sdtr_index = 7;
10840 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10841 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10842 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10843 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10844 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10845 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10846 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10847 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10848 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10849 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10850 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10851 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10852 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10853 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10854 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10855 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10856 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10857 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10858 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10859 asc_dvc->max_sdtr_index = 15;
10860 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10861 AscSetExtraControl(iop_base,
10862 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10863 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10864 AscSetExtraControl(iop_base,
10865 (SEC_ACTIVE_NEGATE |
10866 SEC_ENABLE_FILTER));
10867 }
10868 }
10869 if (asc_dvc->bus_type == ASC_IS_PCI) {
10870 AscSetExtraControl(iop_base,
10871 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10872 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010873
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010874 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
10875 if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
10876 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10877 asc_dvc->bus_type = ASC_IS_ISAPNP;
10878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010879#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010880 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
10881 asc_dvc->cfg->isa_dma_channel =
10882 (uchar)AscGetIsaDmaChannel(iop_base);
10883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010884#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010885 for (i = 0; i <= ASC_MAX_TID; i++) {
10886 asc_dvc->cur_dvc_qng[i] = 0;
10887 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10888 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10889 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10890 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10891 }
10892 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010893}
10894
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010895static ushort __init AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010896{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010897 ASCEEP_CONFIG eep_config_buf;
10898 ASCEEP_CONFIG *eep_config;
10899 PortAddr iop_base;
10900 ushort chksum;
10901 ushort warn_code;
10902 ushort cfg_msw, cfg_lsw;
10903 int i;
10904 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010905
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010906 iop_base = asc_dvc->iop_base;
10907 warn_code = 0;
10908 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10909 AscStopQueueExe(iop_base);
10910 if ((AscStopChip(iop_base) == FALSE) ||
10911 (AscGetChipScsiCtrl(iop_base) != 0)) {
10912 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10913 AscResetChipAndScsiBus(asc_dvc);
10914 DvcSleepMilliSecond((ASC_DCNT)
10915 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10916 }
10917 if (AscIsChipHalted(iop_base) == FALSE) {
10918 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10919 return (warn_code);
10920 }
10921 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10922 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10923 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10924 return (warn_code);
10925 }
10926 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10927 cfg_msw = AscGetChipCfgMsw(iop_base);
10928 cfg_lsw = AscGetChipCfgLsw(iop_base);
10929 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10930 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10931 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10932 AscSetChipCfgMsw(iop_base, cfg_msw);
10933 }
10934 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
10935 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
10936 if (chksum == 0) {
10937 chksum = 0xaa55;
10938 }
10939 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10940 warn_code |= ASC_WARN_AUTO_CONFIG;
10941 if (asc_dvc->cfg->chip_version == 3) {
10942 if (eep_config->cfg_lsw != cfg_lsw) {
10943 warn_code |= ASC_WARN_EEPROM_RECOVER;
10944 eep_config->cfg_lsw =
10945 AscGetChipCfgLsw(iop_base);
10946 }
10947 if (eep_config->cfg_msw != cfg_msw) {
10948 warn_code |= ASC_WARN_EEPROM_RECOVER;
10949 eep_config->cfg_msw =
10950 AscGetChipCfgMsw(iop_base);
10951 }
10952 }
10953 }
10954 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
10955 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
10956 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
10957 eep_config->chksum);
10958 if (chksum != eep_config->chksum) {
10959 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
10960 ASC_CHIP_VER_PCI_ULTRA_3050) {
10961 ASC_DBG(1,
10962 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
10963 eep_config->init_sdtr = 0xFF;
10964 eep_config->disc_enable = 0xFF;
10965 eep_config->start_motor = 0xFF;
10966 eep_config->use_cmd_qng = 0;
10967 eep_config->max_total_qng = 0xF0;
10968 eep_config->max_tag_qng = 0x20;
10969 eep_config->cntl = 0xBFFF;
10970 ASC_EEP_SET_CHIP_ID(eep_config, 7);
10971 eep_config->no_scam = 0;
10972 eep_config->adapter_info[0] = 0;
10973 eep_config->adapter_info[1] = 0;
10974 eep_config->adapter_info[2] = 0;
10975 eep_config->adapter_info[3] = 0;
10976 eep_config->adapter_info[4] = 0;
10977 /* Indicate EEPROM-less board. */
10978 eep_config->adapter_info[5] = 0xBB;
10979 } else {
10980 ASC_PRINT
10981 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
10982 write_eep = 1;
10983 warn_code |= ASC_WARN_EEPROM_CHKSUM;
10984 }
10985 }
10986 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
10987 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
10988 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
10989 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
10990 asc_dvc->start_motor = eep_config->start_motor;
10991 asc_dvc->dvc_cntl = eep_config->cntl;
10992 asc_dvc->no_scam = eep_config->no_scam;
10993 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
10994 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
10995 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
10996 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
10997 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
10998 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
10999 if (!AscTestExternalLram(asc_dvc)) {
11000 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
11001 ASC_IS_PCI_ULTRA)) {
11002 eep_config->max_total_qng =
11003 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
11004 eep_config->max_tag_qng =
11005 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
11006 } else {
11007 eep_config->cfg_msw |= 0x0800;
11008 cfg_msw |= 0x0800;
11009 AscSetChipCfgMsw(iop_base, cfg_msw);
11010 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
11011 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
11012 }
11013 } else {
11014 }
11015 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
11016 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
11017 }
11018 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
11019 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
11020 }
11021 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
11022 eep_config->max_tag_qng = eep_config->max_total_qng;
11023 }
11024 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
11025 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
11026 }
11027 asc_dvc->max_total_qng = eep_config->max_total_qng;
11028 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
11029 eep_config->use_cmd_qng) {
11030 eep_config->disc_enable = eep_config->use_cmd_qng;
11031 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
11032 }
11033 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
11034 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
11035 }
11036 ASC_EEP_SET_CHIP_ID(eep_config,
11037 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
11038 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
11039 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
11040 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
11041 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
11042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011043
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011044 for (i = 0; i <= ASC_MAX_TID; i++) {
11045 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
11046 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
11047 asc_dvc->cfg->sdtr_period_offset[i] =
11048 (uchar)(ASC_DEF_SDTR_OFFSET |
11049 (asc_dvc->host_init_sdtr_index << 4));
11050 }
11051 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
11052 if (write_eep) {
11053 if ((i =
11054 AscSetEEPConfig(iop_base, eep_config,
11055 asc_dvc->bus_type)) != 0) {
11056 ASC_PRINT1
11057 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
11058 i);
11059 } else {
11060 ASC_PRINT
11061 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
11062 }
11063 }
11064 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011065}
11066
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011067static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011068{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011069 int i;
11070 ushort warn_code;
11071 PortAddr iop_base;
11072 ASC_PADDR phy_addr;
11073 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011074
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011075 iop_base = asc_dvc->iop_base;
11076 warn_code = 0;
11077 for (i = 0; i <= ASC_MAX_TID; i++) {
11078 AscPutMCodeInitSDTRAtID(iop_base, i,
11079 asc_dvc->cfg->sdtr_period_offset[i]
11080 );
11081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011082
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011083 AscInitQLinkVar(asc_dvc);
11084 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
11085 asc_dvc->cfg->disc_enable);
11086 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
11087 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011089 /* Align overrun buffer on an 8 byte boundary. */
11090 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
11091 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
11092 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
11093 (uchar *)&phy_addr, 1);
11094 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
11095 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
11096 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011097
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011098 asc_dvc->cfg->mcode_date =
11099 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
11100 asc_dvc->cfg->mcode_version =
11101 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011102
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011103 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
11104 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
11105 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
11106 return (warn_code);
11107 }
11108 if (AscStartChip(iop_base) != 1) {
11109 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
11110 return (warn_code);
11111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011112
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011113 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011114}
11115
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011116static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011117{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011118 PortAddr iop_base;
11119 ushort q_addr;
11120 ushort saved_word;
11121 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011122
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011123 iop_base = asc_dvc->iop_base;
11124 sta = 0;
11125 q_addr = ASC_QNO_TO_QADDR(241);
11126 saved_word = AscReadLramWord(iop_base, q_addr);
11127 AscSetChipLramAddr(iop_base, q_addr);
11128 AscSetChipLramData(iop_base, 0x55AA);
11129 DvcSleepMilliSecond(10);
11130 AscSetChipLramAddr(iop_base, q_addr);
11131 if (AscGetChipLramData(iop_base) == 0x55AA) {
11132 sta = 1;
11133 AscWriteLramWord(iop_base, q_addr, saved_word);
11134 }
11135 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011136}
11137
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011138static int __init AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011139{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011140 uchar read_back;
11141 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011142
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011143 retry = 0;
11144 while (TRUE) {
11145 AscSetChipEEPCmd(iop_base, cmd_reg);
11146 DvcSleepMilliSecond(1);
11147 read_back = AscGetChipEEPCmd(iop_base);
11148 if (read_back == cmd_reg) {
11149 return (1);
11150 }
11151 if (retry++ > ASC_EEP_MAX_RETRY) {
11152 return (0);
11153 }
11154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011155}
11156
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011157static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011158{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011159 ushort read_back;
11160 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011161
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011162 retry = 0;
11163 while (TRUE) {
11164 AscSetChipEEPData(iop_base, data_reg);
11165 DvcSleepMilliSecond(1);
11166 read_back = AscGetChipEEPData(iop_base);
11167 if (read_back == data_reg) {
11168 return (1);
11169 }
11170 if (retry++ > ASC_EEP_MAX_RETRY) {
11171 return (0);
11172 }
11173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011174}
11175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011176static void __init AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011177{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011178 DvcSleepMilliSecond(1);
11179 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011180}
11181
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011182static void __init AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011183{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011184 DvcSleepMilliSecond(20);
11185 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011186}
11187
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011188static ushort __init AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011189{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011190 ushort read_wval;
11191 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011192
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011193 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
11194 AscWaitEEPRead();
11195 cmd_reg = addr | ASC_EEP_CMD_READ;
11196 AscWriteEEPCmdReg(iop_base, cmd_reg);
11197 AscWaitEEPRead();
11198 read_wval = AscGetChipEEPData(iop_base);
11199 AscWaitEEPRead();
11200 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011201}
11202
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011203static ushort __init
11204AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011205{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011206 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011207
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011208 read_wval = AscReadEEPWord(iop_base, addr);
11209 if (read_wval != word_val) {
11210 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
11211 AscWaitEEPRead();
11212 AscWriteEEPDataReg(iop_base, word_val);
11213 AscWaitEEPRead();
11214 AscWriteEEPCmdReg(iop_base,
11215 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
11216 AscWaitEEPWrite();
11217 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
11218 AscWaitEEPRead();
11219 return (AscReadEEPWord(iop_base, addr));
11220 }
11221 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011222}
11223
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011224static ushort __init
11225AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011226{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011227 ushort wval;
11228 ushort sum;
11229 ushort *wbuf;
11230 int cfg_beg;
11231 int cfg_end;
11232 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
11233 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011234
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011235 wbuf = (ushort *)cfg_buf;
11236 sum = 0;
11237 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
11238 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11239 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
11240 sum += *wbuf;
11241 }
11242 if (bus_type & ASC_IS_VL) {
11243 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11244 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11245 } else {
11246 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11247 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11248 }
11249 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11250 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
11251 if (s_addr <= uchar_end_in_config) {
11252 /*
11253 * Swap all char fields - must unswap bytes already swapped
11254 * by AscReadEEPWord().
11255 */
11256 *wbuf = le16_to_cpu(wval);
11257 } else {
11258 /* Don't swap word field at the end - cntl field. */
11259 *wbuf = wval;
11260 }
11261 sum += wval; /* Checksum treats all EEPROM data as words. */
11262 }
11263 /*
11264 * Read the checksum word which will be compared against 'sum'
11265 * by the caller. Word field already swapped.
11266 */
11267 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
11268 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011269}
11270
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011271static int __init
11272AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011273{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011274 int n_error;
11275 ushort *wbuf;
11276 ushort word;
11277 ushort sum;
11278 int s_addr;
11279 int cfg_beg;
11280 int cfg_end;
11281 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011283 wbuf = (ushort *)cfg_buf;
11284 n_error = 0;
11285 sum = 0;
11286 /* Write two config words; AscWriteEEPWord() will swap bytes. */
11287 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11288 sum += *wbuf;
11289 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
11290 n_error++;
11291 }
11292 }
11293 if (bus_type & ASC_IS_VL) {
11294 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11295 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11296 } else {
11297 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11298 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11299 }
11300 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11301 if (s_addr <= uchar_end_in_config) {
11302 /*
11303 * This is a char field. Swap char fields before they are
11304 * swapped again by AscWriteEEPWord().
11305 */
11306 word = cpu_to_le16(*wbuf);
11307 if (word !=
11308 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
11309 n_error++;
11310 }
11311 } else {
11312 /* Don't swap word field at the end - cntl field. */
11313 if (*wbuf !=
11314 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
11315 n_error++;
11316 }
11317 }
11318 sum += *wbuf; /* Checksum calculated from word values. */
11319 }
11320 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
11321 *wbuf = sum;
11322 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
11323 n_error++;
11324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011325
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011326 /* Read EEPROM back again. */
11327 wbuf = (ushort *)cfg_buf;
11328 /*
11329 * Read two config words; Byte-swapping done by AscReadEEPWord().
11330 */
11331 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11332 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
11333 n_error++;
11334 }
11335 }
11336 if (bus_type & ASC_IS_VL) {
11337 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11338 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11339 } else {
11340 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11341 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11342 }
11343 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11344 if (s_addr <= uchar_end_in_config) {
11345 /*
11346 * Swap all char fields. Must unswap bytes already swapped
11347 * by AscReadEEPWord().
11348 */
11349 word =
11350 le16_to_cpu(AscReadEEPWord
11351 (iop_base, (uchar)s_addr));
11352 } else {
11353 /* Don't swap word field at the end - cntl field. */
11354 word = AscReadEEPWord(iop_base, (uchar)s_addr);
11355 }
11356 if (*wbuf != word) {
11357 n_error++;
11358 }
11359 }
11360 /* Read checksum; Byte swapping not needed. */
11361 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
11362 n_error++;
11363 }
11364 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011365}
11366
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011367static int __init
11368AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011369{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011370 int retry;
11371 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011372
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011373 retry = 0;
11374 while (TRUE) {
11375 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
11376 bus_type)) == 0) {
11377 break;
11378 }
11379 if (++retry > ASC_EEP_MAX_RETRY) {
11380 break;
11381 }
11382 }
11383 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011384}
11385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011386static void
11387AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011388{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011389 uchar dvc_type;
11390 ASC_SCSI_BIT_ID_TYPE tid_bits;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011391
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011392 dvc_type = ASC_INQ_DVC_TYPE(inq);
11393 tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011394
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011395 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
11396 if (!(asc_dvc->init_sdtr & tid_bits)) {
11397 if ((dvc_type == TYPE_ROM) &&
11398 (AscCompareString((uchar *)inq->vendor_id,
11399 (uchar *)"HP ", 3) == 0)) {
11400 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
11401 }
11402 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
11403 if ((dvc_type == TYPE_PROCESSOR) ||
11404 (dvc_type == TYPE_SCANNER) ||
11405 (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) {
11406 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
11407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011408
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011409 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
11410 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
11411 tid_no,
11412 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
11413 }
11414 }
11415 }
11416 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011417}
11418
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011419static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011420{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011421 if ((inq->add_len >= 32) &&
11422 (AscCompareString((uchar *)inq->vendor_id,
11423 (uchar *)"QUANTUM XP34301", 15) == 0) &&
11424 (AscCompareString((uchar *)inq->product_rev_level,
11425 (uchar *)"1071", 4) == 0)) {
11426 return 0;
11427 }
11428 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011429}
11430
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011431static void
11432AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011433{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011434 ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
11435 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011436
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011437 orig_init_sdtr = asc_dvc->init_sdtr;
11438 orig_use_tagged_qng = asc_dvc->use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011439
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011440 asc_dvc->init_sdtr &= ~tid_bit;
11441 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
11442 asc_dvc->use_tagged_qng &= ~tid_bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011443
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011444 if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
11445 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
11446 asc_dvc->init_sdtr |= tid_bit;
11447 }
11448 if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
11449 ASC_INQ_CMD_QUEUE(inq)) {
11450 if (AscTagQueuingSafe(inq)) {
11451 asc_dvc->use_tagged_qng |= tid_bit;
11452 asc_dvc->cfg->can_tagged_qng |= tid_bit;
11453 }
11454 }
11455 }
11456 if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
11457 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
11458 asc_dvc->cfg->disc_enable);
11459 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
11460 asc_dvc->use_tagged_qng);
11461 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
11462 asc_dvc->cfg->can_tagged_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011463
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011464 asc_dvc->max_dvc_qng[tid_no] =
11465 asc_dvc->cfg->max_tag_qng[tid_no];
11466 AscWriteLramByte(asc_dvc->iop_base,
11467 (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no),
11468 asc_dvc->max_dvc_qng[tid_no]);
11469 }
11470 if (orig_init_sdtr != asc_dvc->init_sdtr) {
11471 AscAsyncFix(asc_dvc, tid_no, inq);
11472 }
11473 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011474}
11475
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011476static int AscCompareString(uchar *str1, uchar *str2, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011477{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011478 int i;
11479 int diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011481 for (i = 0; i < len; i++) {
11482 diff = (int)(str1[i] - str2[i]);
11483 if (diff != 0)
11484 return (diff);
11485 }
11486 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011487}
11488
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011489static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011490{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011491 uchar byte_data;
11492 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011494 if (isodd_word(addr)) {
11495 AscSetChipLramAddr(iop_base, addr - 1);
11496 word_data = AscGetChipLramData(iop_base);
11497 byte_data = (uchar)((word_data >> 8) & 0xFF);
11498 } else {
11499 AscSetChipLramAddr(iop_base, addr);
11500 word_data = AscGetChipLramData(iop_base);
11501 byte_data = (uchar)(word_data & 0xFF);
11502 }
11503 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011504}
Linus Torvalds1da177e2005-04-16 15:20:36 -070011505
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011506static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
11507{
11508 ushort word_data;
11509
11510 AscSetChipLramAddr(iop_base, addr);
11511 word_data = AscGetChipLramData(iop_base);
11512 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011513}
11514
11515#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011516static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011517{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011518 ushort val_low, val_high;
11519 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011520
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011521 AscSetChipLramAddr(iop_base, addr);
11522 val_low = AscGetChipLramData(iop_base);
11523 val_high = AscGetChipLramData(iop_base);
11524 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
11525 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011526}
11527#endif /* CC_VERY_LONG_SG_LIST */
11528
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011529static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011530{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011531 AscSetChipLramAddr(iop_base, addr);
11532 AscSetChipLramData(iop_base, word_val);
11533 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011534}
11535
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011536static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011537{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011538 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011539
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011540 if (isodd_word(addr)) {
11541 addr--;
11542 word_data = AscReadLramWord(iop_base, addr);
11543 word_data &= 0x00FF;
11544 word_data |= (((ushort)byte_val << 8) & 0xFF00);
11545 } else {
11546 word_data = AscReadLramWord(iop_base, addr);
11547 word_data &= 0xFF00;
11548 word_data |= ((ushort)byte_val & 0x00FF);
11549 }
11550 AscWriteLramWord(iop_base, addr, word_data);
11551 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011552}
11553
11554/*
11555 * Copy 2 bytes to LRAM.
11556 *
11557 * The source data is assumed to be in little-endian order in memory
11558 * and is maintained in little-endian order when written to LRAM.
11559 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011560static void
11561AscMemWordCopyPtrToLram(PortAddr iop_base,
11562 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011563{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011564 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011565
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011566 AscSetChipLramAddr(iop_base, s_addr);
11567 for (i = 0; i < 2 * words; i += 2) {
11568 /*
11569 * On a little-endian system the second argument below
11570 * produces a little-endian ushort which is written to
11571 * LRAM in little-endian order. On a big-endian system
11572 * the second argument produces a big-endian ushort which
11573 * is "transparently" byte-swapped by outpw() and written
11574 * in little-endian order to LRAM.
11575 */
11576 outpw(iop_base + IOP_RAM_DATA,
11577 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
11578 }
11579 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011580}
11581
11582/*
11583 * Copy 4 bytes to LRAM.
11584 *
11585 * The source data is assumed to be in little-endian order in memory
11586 * and is maintained in little-endian order when writen to LRAM.
11587 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011588static void
11589AscMemDWordCopyPtrToLram(PortAddr iop_base,
11590 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011591{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011592 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011593
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011594 AscSetChipLramAddr(iop_base, s_addr);
11595 for (i = 0; i < 4 * dwords; i += 4) {
11596 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11597 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11598 }
11599 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011600}
11601
11602/*
11603 * Copy 2 bytes from LRAM.
11604 *
11605 * The source data is assumed to be in little-endian order in LRAM
11606 * and is maintained in little-endian order when written to memory.
11607 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011608static void
11609AscMemWordCopyPtrFromLram(PortAddr iop_base,
11610 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011611{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011612 int i;
11613 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011614
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011615 AscSetChipLramAddr(iop_base, s_addr);
11616 for (i = 0; i < 2 * words; i += 2) {
11617 word = inpw(iop_base + IOP_RAM_DATA);
11618 d_buffer[i] = word & 0xff;
11619 d_buffer[i + 1] = (word >> 8) & 0xff;
11620 }
11621 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011622}
11623
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011624static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011625{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011626 ASC_DCNT sum;
11627 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011629 sum = 0L;
11630 for (i = 0; i < words; i++, s_addr += 2) {
11631 sum += AscReadLramWord(iop_base, s_addr);
11632 }
11633 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011634}
11635
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011636static void
11637AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011638{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011639 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011640
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011641 AscSetChipLramAddr(iop_base, s_addr);
11642 for (i = 0; i < words; i++) {
11643 AscSetChipLramData(iop_base, set_wval);
11644 }
11645 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011646}
11647
Linus Torvalds1da177e2005-04-16 15:20:36 -070011648/*
11649 * --- Adv Library Functions
11650 */
11651
11652/* a_mcode.h */
11653
11654/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011655static unsigned char _adv_asc3550_buf[] = {
11656 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11657 0x01, 0x00, 0x48, 0xe4,
11658 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11659 0x28, 0x0e, 0x9e, 0xe7,
11660 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11661 0x55, 0xf0, 0x01, 0xf6,
11662 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11663 0x00, 0xec, 0x85, 0xf0,
11664 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11665 0x86, 0xf0, 0xb4, 0x00,
11666 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11667 0xaa, 0x18, 0x02, 0x80,
11668 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11669 0x00, 0x57, 0x01, 0xea,
11670 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11671 0x03, 0xe6, 0xb6, 0x00,
11672 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11673 0x02, 0x4a, 0xb9, 0x54,
11674 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11675 0x3e, 0x00, 0x80, 0x00,
11676 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11677 0x74, 0x01, 0x76, 0x01,
11678 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11679 0x4c, 0x1c, 0xbb, 0x55,
11680 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11681 0x03, 0xf7, 0x06, 0xf7,
11682 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11683 0x30, 0x13, 0x64, 0x15,
11684 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11685 0x04, 0xea, 0x5d, 0xf0,
11686 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11687 0xcc, 0x00, 0x20, 0x01,
11688 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11689 0x40, 0x13, 0x30, 0x1c,
11690 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11691 0x59, 0xf0, 0xa7, 0xf0,
11692 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11693 0xa4, 0x00, 0xb5, 0x00,
11694 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11695 0x14, 0x0e, 0x02, 0x10,
11696 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11697 0x10, 0x15, 0x14, 0x15,
11698 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11699 0x91, 0x44, 0x0a, 0x45,
11700 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11701 0x83, 0x59, 0x05, 0xe6,
11702 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11703 0x02, 0xfa, 0x03, 0xfa,
11704 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11705 0x9e, 0x00, 0xa8, 0x00,
11706 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11707 0x7a, 0x01, 0xc0, 0x01,
11708 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11709 0x69, 0x08, 0xba, 0x08,
11710 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11711 0xf1, 0x10, 0x06, 0x12,
11712 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11713 0x8a, 0x15, 0xc6, 0x17,
11714 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11715 0x0e, 0x47, 0x48, 0x47,
11716 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11717 0x14, 0x56, 0x77, 0x57,
11718 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11719 0xf0, 0x29, 0x02, 0xfe,
11720 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11721 0xfe, 0x80, 0x01, 0xff,
11722 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11723 0x00, 0xfe, 0x57, 0x24,
11724 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11725 0x00, 0x00, 0xff, 0x08,
11726 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11727 0xff, 0xff, 0xff, 0x0f,
11728 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11729 0xfe, 0x04, 0xf7, 0xcf,
11730 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11731 0x0b, 0x3c, 0x2a, 0xfe,
11732 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11733 0xfe, 0xf0, 0x01, 0xfe,
11734 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11735 0x02, 0xfe, 0xd4, 0x0c,
11736 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11737 0x1c, 0x05, 0xfe, 0xa6,
11738 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11739 0xf0, 0xfe, 0x86, 0x02,
11740 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11741 0xfe, 0x46, 0xf0, 0xfe,
11742 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11743 0x44, 0x02, 0xfe, 0x44,
11744 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11745 0xa0, 0x17, 0x06, 0x18,
11746 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11747 0x1e, 0x1c, 0xfe, 0xe9,
11748 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11749 0x0a, 0x6b, 0x01, 0x9e,
11750 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11751 0x01, 0x82, 0xfe, 0xbd,
11752 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11753 0x58, 0x1c, 0x17, 0x06,
11754 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11755 0xfe, 0x94, 0x02, 0xfe,
11756 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11757 0x01, 0xfe, 0x54, 0x0f,
11758 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11759 0x69, 0x10, 0x17, 0x06,
11760 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11761 0xf6, 0xc7, 0x01, 0xfe,
11762 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11763 0x02, 0x29, 0x0a, 0x40,
11764 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11765 0x58, 0x0a, 0x99, 0x01,
11766 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11767 0x2a, 0x46, 0xfe, 0x02,
11768 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11769 0x01, 0xfe, 0x07, 0x4b,
11770 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11771 0xfe, 0x56, 0x03, 0xfe,
11772 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11773 0xfe, 0x9f, 0xf0, 0xfe,
11774 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11775 0x1c, 0xeb, 0x09, 0x04,
11776 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11777 0x01, 0x0e, 0xac, 0x75,
11778 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11779 0xfe, 0x82, 0xf0, 0xfe,
11780 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11781 0x32, 0x1f, 0xfe, 0xb4,
11782 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11783 0x0a, 0xf0, 0xfe, 0x7a,
11784 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11785 0x01, 0x33, 0x8f, 0xfe,
11786 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11787 0xf7, 0xfe, 0x48, 0x1c,
11788 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11789 0x0a, 0xca, 0x01, 0x0e,
11790 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11791 0x2c, 0x01, 0x33, 0x8f,
11792 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11793 0xfe, 0x3c, 0x04, 0x1f,
11794 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11795 0x12, 0x2b, 0xff, 0x02,
11796 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11797 0x22, 0x30, 0x2e, 0xd5,
11798 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11799 0xfe, 0x4c, 0x54, 0x64,
11800 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11801 0xfe, 0x2a, 0x13, 0x2f,
11802 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11803 0xd3, 0xfa, 0xef, 0x86,
11804 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11805 0x1d, 0xfe, 0x1c, 0x12,
11806 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11807 0x70, 0x0c, 0x02, 0x22,
11808 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11809 0x01, 0x33, 0x02, 0x29,
11810 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11811 0x80, 0xfe, 0x31, 0xe4,
11812 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11813 0xfe, 0x70, 0x12, 0x49,
11814 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11815 0x80, 0x05, 0xfe, 0x31,
11816 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11817 0x28, 0xfe, 0x42, 0x12,
11818 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11819 0x11, 0xfe, 0xe3, 0x00,
11820 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11821 0x64, 0x05, 0x83, 0x24,
11822 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11823 0x09, 0x48, 0x01, 0x08,
11824 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11825 0x86, 0x24, 0x06, 0x12,
11826 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11827 0x01, 0xa7, 0x14, 0x92,
11828 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11829 0x02, 0x22, 0x05, 0xfe,
11830 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11831 0x47, 0x01, 0xa7, 0x26,
11832 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11833 0x01, 0xfe, 0xaa, 0x14,
11834 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11835 0x05, 0x50, 0xb4, 0x0c,
11836 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11837 0x13, 0x01, 0xfe, 0x14,
11838 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11839 0xff, 0x02, 0x00, 0x57,
11840 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11841 0x72, 0x06, 0x49, 0x04,
11842 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11843 0x06, 0x11, 0x9a, 0x01,
11844 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11845 0x01, 0xa7, 0xec, 0x72,
11846 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11847 0xfe, 0x0a, 0xf0, 0xfe,
11848 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11849 0x8d, 0x81, 0x02, 0x22,
11850 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11851 0x01, 0x08, 0x15, 0x00,
11852 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11853 0x00, 0x02, 0xfe, 0x32,
11854 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11855 0xfe, 0x1b, 0x00, 0x01,
11856 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11857 0x08, 0x15, 0x06, 0x01,
11858 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11859 0x9a, 0x81, 0x4b, 0x1d,
11860 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11861 0x45, 0xfe, 0x32, 0x12,
11862 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11863 0xfe, 0x32, 0x07, 0x8d,
11864 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11865 0x06, 0x15, 0x19, 0x02,
11866 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11867 0x90, 0x77, 0xfe, 0xca,
11868 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11869 0x10, 0xfe, 0x0e, 0x12,
11870 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11871 0x83, 0xe7, 0xc4, 0xa1,
11872 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11873 0x40, 0x12, 0x58, 0x01,
11874 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11875 0x51, 0x83, 0xfb, 0xfe,
11876 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11877 0xfe, 0x40, 0x50, 0xfe,
11878 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11879 0xfe, 0x2a, 0x12, 0xfe,
11880 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11881 0x85, 0x01, 0xa8, 0xfe,
11882 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11883 0x18, 0x57, 0xfb, 0xfe,
11884 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11885 0x0c, 0x39, 0x18, 0x3a,
11886 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11887 0x11, 0x65, 0xfe, 0x48,
11888 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11889 0xdd, 0xb8, 0xfe, 0x80,
11890 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11891 0xfe, 0x7a, 0x08, 0x8d,
11892 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11893 0x10, 0x61, 0x04, 0x06,
11894 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11895 0x12, 0xfe, 0x2e, 0x1c,
11896 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11897 0x52, 0x12, 0xfe, 0x2c,
11898 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11899 0x08, 0xfe, 0x8a, 0x10,
11900 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11901 0x24, 0x0a, 0xab, 0xfe,
11902 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11903 0x1c, 0x12, 0xb5, 0xfe,
11904 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11905 0x1c, 0x06, 0x16, 0x9d,
11906 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11907 0x14, 0x92, 0x01, 0x33,
11908 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11909 0xfe, 0x74, 0x18, 0x1c,
11910 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11911 0x01, 0xe6, 0x1e, 0x27,
11912 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11913 0x09, 0x04, 0x6a, 0xfe,
11914 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11915 0xfe, 0x83, 0x80, 0xfe,
11916 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11917 0x27, 0xfe, 0x40, 0x59,
11918 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11919 0x7c, 0xbe, 0x54, 0xbf,
11920 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11921 0x79, 0x56, 0x68, 0x57,
11922 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11923 0xa2, 0x23, 0x0c, 0x7b,
11924 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11925 0x16, 0xd7, 0x79, 0x39,
11926 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11927 0xfe, 0x10, 0x58, 0xfe,
11928 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
11929 0x19, 0x16, 0xd7, 0x09,
11930 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
11931 0xfe, 0x10, 0x90, 0xfe,
11932 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
11933 0x11, 0x9b, 0x09, 0x04,
11934 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
11935 0xfe, 0x0c, 0x58, 0xfe,
11936 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
11937 0x0b, 0xfe, 0x1a, 0x12,
11938 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
11939 0x14, 0x7a, 0x01, 0x33,
11940 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
11941 0xfe, 0xed, 0x19, 0xbf,
11942 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
11943 0x34, 0xfe, 0x74, 0x10,
11944 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
11945 0x84, 0x05, 0xcb, 0x1c,
11946 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
11947 0xf0, 0xfe, 0xc4, 0x0a,
11948 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
11949 0xce, 0xf0, 0xfe, 0xca,
11950 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
11951 0x22, 0x00, 0x02, 0x5a,
11952 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
11953 0xfe, 0xd0, 0xf0, 0xfe,
11954 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
11955 0x4c, 0xfe, 0x10, 0x10,
11956 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
11957 0x2a, 0x13, 0xfe, 0x4e,
11958 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
11959 0x16, 0x32, 0x2a, 0x73,
11960 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
11961 0x32, 0x8c, 0xfe, 0x48,
11962 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
11963 0xdb, 0x10, 0x11, 0xfe,
11964 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
11965 0x22, 0x30, 0x2e, 0xd8,
11966 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
11967 0x45, 0x0f, 0xfe, 0x42,
11968 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
11969 0x09, 0x04, 0x0b, 0xfe,
11970 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
11971 0x00, 0x21, 0xfe, 0xa6,
11972 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
11973 0xfe, 0xe2, 0x10, 0x01,
11974 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
11975 0x01, 0x6f, 0x02, 0x29,
11976 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
11977 0x01, 0x86, 0x3e, 0x0b,
11978 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
11979 0x3e, 0x0b, 0x0f, 0xfe,
11980 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
11981 0xe8, 0x59, 0x11, 0x2d,
11982 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
11983 0x04, 0x0b, 0x84, 0x3e,
11984 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
11985 0x09, 0x04, 0x1b, 0xfe,
11986 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
11987 0x1c, 0x1c, 0xfe, 0x9d,
11988 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
11989 0xfe, 0x15, 0x00, 0xfe,
11990 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
11991 0x0f, 0xfe, 0x47, 0x00,
11992 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
11993 0xab, 0x70, 0x05, 0x6b,
11994 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
11995 0x1c, 0x42, 0x59, 0x01,
11996 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
11997 0x00, 0x37, 0x97, 0x01,
11998 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
11999 0x1d, 0xfe, 0xce, 0x45,
12000 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
12001 0x57, 0x05, 0x51, 0xfe,
12002 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
12003 0x46, 0x09, 0x04, 0x1d,
12004 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
12005 0x99, 0x01, 0x0e, 0xfe,
12006 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
12007 0xfe, 0xee, 0x14, 0xee,
12008 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
12009 0x13, 0x02, 0x29, 0x1e,
12010 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
12011 0xce, 0x1e, 0x2d, 0x47,
12012 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
12013 0x12, 0x4d, 0x01, 0xfe,
12014 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
12015 0xf0, 0x0d, 0xfe, 0x02,
12016 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
12017 0xf6, 0xfe, 0x34, 0x01,
12018 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
12019 0xaf, 0xfe, 0x02, 0xea,
12020 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
12021 0x05, 0xfe, 0x38, 0x01,
12022 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
12023 0x0c, 0xfe, 0x62, 0x01,
12024 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
12025 0x03, 0x23, 0x03, 0x1e,
12026 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
12027 0x71, 0x13, 0xfe, 0x24,
12028 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
12029 0xdc, 0xfe, 0x73, 0x57,
12030 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
12031 0x80, 0x5d, 0x03, 0xfe,
12032 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
12033 0x75, 0x03, 0x09, 0x04,
12034 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
12035 0xfe, 0x1e, 0x80, 0xe1,
12036 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
12037 0x90, 0xa3, 0xfe, 0x3c,
12038 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
12039 0x16, 0x2f, 0x07, 0x2d,
12040 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
12041 0xe8, 0x11, 0xfe, 0xe9,
12042 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
12043 0x1e, 0x1c, 0xfe, 0x14,
12044 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
12045 0x09, 0x04, 0x4f, 0xfe,
12046 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
12047 0x40, 0x12, 0x20, 0x63,
12048 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
12049 0x1c, 0x05, 0xfe, 0xac,
12050 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
12051 0xfe, 0xb0, 0x00, 0xfe,
12052 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
12053 0x24, 0x69, 0x12, 0xc9,
12054 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
12055 0x90, 0x4d, 0xfe, 0x91,
12056 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
12057 0xfe, 0x90, 0x4d, 0xfe,
12058 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
12059 0x46, 0x1e, 0x20, 0xed,
12060 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
12061 0x70, 0xfe, 0x14, 0x1c,
12062 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
12063 0xfe, 0x07, 0xe6, 0x1d,
12064 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
12065 0xfa, 0xef, 0xfe, 0x42,
12066 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
12067 0xfe, 0x36, 0x12, 0xf0,
12068 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
12069 0x3d, 0x75, 0x07, 0x10,
12070 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
12071 0x10, 0x07, 0x7e, 0x45,
12072 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
12073 0xfe, 0x01, 0xec, 0x97,
12074 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
12075 0x27, 0x01, 0xda, 0xfe,
12076 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
12077 0xfe, 0x48, 0x12, 0x07,
12078 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
12079 0xfe, 0x3e, 0x11, 0x07,
12080 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
12081 0x11, 0x07, 0x19, 0xfe,
12082 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
12083 0x01, 0x08, 0x8c, 0x43,
12084 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
12085 0x7e, 0x02, 0x29, 0x2b,
12086 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
12087 0xfc, 0x10, 0x09, 0x04,
12088 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
12089 0xc6, 0x10, 0x1e, 0x58,
12090 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
12091 0x54, 0x18, 0x55, 0x23,
12092 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
12093 0xa5, 0xc0, 0x38, 0xc1,
12094 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
12095 0x05, 0xfa, 0x4e, 0xfe,
12096 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
12097 0x0c, 0x56, 0x18, 0x57,
12098 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
12099 0x00, 0x56, 0xfe, 0xa1,
12100 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
12101 0x58, 0xfe, 0x1f, 0x40,
12102 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
12103 0x31, 0x57, 0xfe, 0x44,
12104 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
12105 0x8a, 0x50, 0x05, 0x39,
12106 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
12107 0x12, 0xcd, 0x02, 0x5b,
12108 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
12109 0x2f, 0x07, 0x9b, 0x21,
12110 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
12111 0x39, 0x68, 0x3a, 0xfe,
12112 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
12113 0x51, 0xfe, 0x8e, 0x51,
12114 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
12115 0x01, 0x08, 0x25, 0x32,
12116 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
12117 0x3b, 0x02, 0x44, 0x01,
12118 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
12119 0x01, 0x08, 0x1f, 0xa2,
12120 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
12121 0x00, 0x28, 0x84, 0x49,
12122 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
12123 0x78, 0x3d, 0xfe, 0xda,
12124 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
12125 0x05, 0xc6, 0x28, 0x84,
12126 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
12127 0x14, 0xfe, 0x03, 0x17,
12128 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
12129 0xfe, 0xaa, 0x14, 0x02,
12130 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
12131 0x21, 0x44, 0x01, 0xfe,
12132 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
12133 0xfe, 0x4a, 0xf4, 0x0b,
12134 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
12135 0x85, 0x02, 0x5b, 0x05,
12136 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
12137 0xd8, 0x14, 0x02, 0x5c,
12138 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
12139 0x01, 0x08, 0x23, 0x72,
12140 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
12141 0x12, 0x5e, 0x2b, 0x01,
12142 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
12143 0x1c, 0xfe, 0xff, 0x7f,
12144 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
12145 0x57, 0x48, 0x8b, 0x1c,
12146 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
12147 0x00, 0x57, 0x48, 0x8b,
12148 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
12149 0x03, 0x0a, 0x50, 0x01,
12150 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
12151 0x54, 0xfe, 0x00, 0xf4,
12152 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
12153 0x03, 0x7c, 0x63, 0x27,
12154 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
12155 0xfe, 0x82, 0x4a, 0xfe,
12156 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
12157 0x42, 0x48, 0x5f, 0x60,
12158 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
12159 0x1f, 0xfe, 0xa2, 0x14,
12160 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
12161 0xcc, 0x12, 0x49, 0x04,
12162 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
12163 0xe8, 0x13, 0x3b, 0x13,
12164 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
12165 0xa1, 0xff, 0x02, 0x83,
12166 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
12167 0x13, 0x06, 0xfe, 0x56,
12168 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
12169 0x64, 0x00, 0x17, 0x93,
12170 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
12171 0xc8, 0x00, 0x8e, 0xe4,
12172 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
12173 0x01, 0xba, 0xfe, 0x4e,
12174 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
12175 0xfe, 0x60, 0x14, 0xfe,
12176 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
12177 0xfe, 0x22, 0x13, 0x1c,
12178 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
12179 0xfe, 0x9c, 0x14, 0xb7,
12180 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
12181 0xfe, 0x9c, 0x14, 0xb7,
12182 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
12183 0xfe, 0xb4, 0x56, 0xfe,
12184 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
12185 0xe5, 0x15, 0x0b, 0x01,
12186 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
12187 0x49, 0x01, 0x08, 0x03,
12188 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
12189 0x15, 0x06, 0x01, 0x08,
12190 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
12191 0x4a, 0x01, 0x08, 0x03,
12192 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
12193 0xfe, 0x49, 0xf4, 0x00,
12194 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
12195 0x08, 0x2f, 0x07, 0xfe,
12196 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
12197 0x01, 0x43, 0x1e, 0xcd,
12198 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
12199 0xed, 0x88, 0x07, 0x10,
12200 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
12201 0x80, 0x01, 0x0e, 0x88,
12202 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
12203 0x88, 0x03, 0x0a, 0x42,
12204 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
12205 0xfe, 0x80, 0x80, 0xf2,
12206 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
12207 0x01, 0x82, 0x03, 0x17,
12208 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
12209 0xfe, 0x24, 0x1c, 0xfe,
12210 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
12211 0x91, 0x1d, 0x66, 0xfe,
12212 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
12213 0xda, 0x10, 0x17, 0x10,
12214 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
12215 0x05, 0xfe, 0x66, 0x01,
12216 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
12217 0xfe, 0x3c, 0x50, 0x66,
12218 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
12219 0x40, 0x16, 0xfe, 0xb6,
12220 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
12221 0x10, 0x71, 0xfe, 0x83,
12222 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
12223 0xfe, 0x62, 0x16, 0xfe,
12224 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
12225 0xfe, 0x98, 0xe7, 0x00,
12226 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
12227 0xfe, 0x30, 0xbc, 0xfe,
12228 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12229 0xc5, 0x90, 0xfe, 0x9a,
12230 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
12231 0x42, 0x10, 0xfe, 0x02,
12232 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
12233 0xfe, 0x1d, 0xf7, 0x4f,
12234 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
12235 0x47, 0xfe, 0x83, 0x58,
12236 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
12237 0xfe, 0xdd, 0x00, 0x63,
12238 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
12239 0x06, 0x37, 0x95, 0xa9,
12240 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
12241 0x18, 0x1c, 0x1a, 0x5d,
12242 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
12243 0xe1, 0x10, 0x78, 0x2c,
12244 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
12245 0x13, 0x3c, 0x8a, 0x0a,
12246 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
12247 0xe3, 0xfe, 0x00, 0xcc,
12248 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
12249 0x0e, 0xf2, 0x01, 0x6f,
12250 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
12251 0xf6, 0xfe, 0xd6, 0xf0,
12252 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
12253 0x15, 0x00, 0x59, 0x76,
12254 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
12255 0x11, 0x2d, 0x01, 0x6f,
12256 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
12257 0xc8, 0xfe, 0x48, 0x55,
12258 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
12259 0x99, 0x01, 0x0e, 0xf0,
12260 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
12261 0x75, 0x03, 0x0a, 0x42,
12262 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
12263 0x0e, 0x73, 0x75, 0x03,
12264 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
12265 0xfe, 0x3a, 0x45, 0x5b,
12266 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
12267 0xfe, 0x02, 0xe6, 0x1b,
12268 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
12269 0xfe, 0x94, 0x00, 0xfe,
12270 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
12271 0xe6, 0x2c, 0xfe, 0x4e,
12272 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
12273 0x03, 0x07, 0x7a, 0xfe,
12274 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12275 0x07, 0x1b, 0xfe, 0x5a,
12276 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
12277 0x24, 0x2c, 0xdc, 0x07,
12278 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
12279 0x9f, 0xad, 0x03, 0x14,
12280 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
12281 0x03, 0x25, 0xfe, 0xca,
12282 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
12283 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012284};
12285
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012286static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
12287static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012288
12289/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012290static unsigned char _adv_asc38C0800_buf[] = {
12291 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
12292 0x01, 0x00, 0x48, 0xe4,
12293 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
12294 0x1c, 0x0f, 0x00, 0xf6,
12295 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
12296 0x09, 0xe7, 0x55, 0xf0,
12297 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
12298 0x18, 0xf4, 0x08, 0x00,
12299 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
12300 0x86, 0xf0, 0xb1, 0xf0,
12301 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
12302 0x3c, 0x00, 0xbb, 0x00,
12303 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
12304 0xba, 0x13, 0x18, 0x40,
12305 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
12306 0x6e, 0x01, 0x74, 0x01,
12307 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
12308 0xc0, 0x00, 0x01, 0x01,
12309 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
12310 0x08, 0x12, 0x02, 0x4a,
12311 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
12312 0x5d, 0xf0, 0x02, 0xfa,
12313 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
12314 0x68, 0x01, 0x6a, 0x01,
12315 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
12316 0x06, 0x13, 0x4c, 0x1c,
12317 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
12318 0x0f, 0x00, 0x47, 0x00,
12319 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
12320 0x4e, 0x1c, 0x10, 0x44,
12321 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
12322 0x05, 0x00, 0x34, 0x00,
12323 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
12324 0x42, 0x0c, 0x12, 0x0f,
12325 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
12326 0x00, 0x4e, 0x42, 0x54,
12327 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
12328 0x59, 0xf0, 0xb8, 0xf0,
12329 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
12330 0x19, 0x00, 0x33, 0x00,
12331 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
12332 0xe7, 0x00, 0xe2, 0x03,
12333 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
12334 0x12, 0x13, 0x24, 0x14,
12335 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
12336 0x36, 0x1c, 0x08, 0x44,
12337 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
12338 0x3a, 0x55, 0x83, 0x55,
12339 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
12340 0x0c, 0xf0, 0x04, 0xf8,
12341 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
12342 0xa8, 0x00, 0xaa, 0x00,
12343 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
12344 0xc4, 0x01, 0xc6, 0x01,
12345 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
12346 0x68, 0x08, 0x69, 0x08,
12347 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
12348 0xed, 0x10, 0xf1, 0x10,
12349 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
12350 0x1e, 0x13, 0x46, 0x14,
12351 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
12352 0xca, 0x18, 0xe6, 0x19,
12353 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
12354 0xf0, 0x2b, 0x02, 0xfe,
12355 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
12356 0xfe, 0x84, 0x01, 0xff,
12357 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12358 0x00, 0xfe, 0x57, 0x24,
12359 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
12360 0x00, 0x00, 0xff, 0x08,
12361 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12362 0xff, 0xff, 0xff, 0x11,
12363 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12364 0xfe, 0x04, 0xf7, 0xd6,
12365 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
12366 0x0a, 0x42, 0x2c, 0xfe,
12367 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
12368 0xfe, 0xf4, 0x01, 0xfe,
12369 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
12370 0x02, 0xfe, 0xc8, 0x0d,
12371 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
12372 0x1c, 0x03, 0xfe, 0xa6,
12373 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
12374 0xf0, 0xfe, 0x8a, 0x02,
12375 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
12376 0xfe, 0x46, 0xf0, 0xfe,
12377 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
12378 0x48, 0x02, 0xfe, 0x44,
12379 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
12380 0xaa, 0x18, 0x06, 0x14,
12381 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
12382 0x1e, 0x1c, 0xfe, 0xe9,
12383 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
12384 0x09, 0x70, 0x01, 0xa8,
12385 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
12386 0x01, 0x87, 0xfe, 0xbd,
12387 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
12388 0x58, 0x1c, 0x18, 0x06,
12389 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
12390 0xfe, 0x98, 0x02, 0xfe,
12391 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
12392 0x01, 0xfe, 0x48, 0x10,
12393 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
12394 0x69, 0x10, 0x18, 0x06,
12395 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
12396 0xf6, 0xce, 0x01, 0xfe,
12397 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
12398 0x82, 0x16, 0x02, 0x2b,
12399 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
12400 0xfe, 0x41, 0x58, 0x09,
12401 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
12402 0x82, 0x16, 0x02, 0x2b,
12403 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
12404 0xfe, 0x77, 0x57, 0xfe,
12405 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
12406 0xfe, 0x40, 0x1c, 0x1c,
12407 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
12408 0x03, 0xfe, 0x11, 0xf0,
12409 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
12410 0xfe, 0x11, 0x00, 0x02,
12411 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
12412 0x21, 0x22, 0xa3, 0xb7,
12413 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
12414 0x12, 0xd1, 0x1c, 0xd9,
12415 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
12416 0xfe, 0xe4, 0x00, 0x27,
12417 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
12418 0x06, 0xf0, 0xfe, 0xc8,
12419 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
12420 0x70, 0x28, 0x17, 0xfe,
12421 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
12422 0xf9, 0x2c, 0x99, 0x19,
12423 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
12424 0x74, 0x01, 0xaf, 0x8c,
12425 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
12426 0x8d, 0x51, 0x64, 0x79,
12427 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
12428 0xfe, 0x6a, 0x02, 0x02,
12429 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
12430 0xfe, 0x3c, 0x04, 0x3b,
12431 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
12432 0x00, 0x10, 0x01, 0x0b,
12433 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
12434 0xfe, 0x4c, 0x44, 0xfe,
12435 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
12436 0xda, 0x4f, 0x79, 0x2a,
12437 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
12438 0xfe, 0x2a, 0x13, 0x32,
12439 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
12440 0x54, 0x6b, 0xda, 0xfe,
12441 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
12442 0x08, 0x13, 0x32, 0x07,
12443 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
12444 0x08, 0x05, 0x06, 0x4d,
12445 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
12446 0x2d, 0x12, 0xfe, 0xe6,
12447 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
12448 0x02, 0x2b, 0xfe, 0x42,
12449 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12450 0xfe, 0x87, 0x80, 0xfe,
12451 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
12452 0x07, 0x19, 0xfe, 0x7c,
12453 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
12454 0x17, 0xfe, 0x90, 0x05,
12455 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
12456 0xa0, 0x00, 0x28, 0xfe,
12457 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
12458 0x34, 0xfe, 0x89, 0x48,
12459 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
12460 0x12, 0xfe, 0xe3, 0x00,
12461 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
12462 0x70, 0x05, 0x88, 0x25,
12463 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
12464 0x09, 0x48, 0xff, 0x02,
12465 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
12466 0x08, 0x53, 0x05, 0xcb,
12467 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
12468 0x05, 0x1b, 0xfe, 0x22,
12469 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
12470 0x0d, 0x00, 0x01, 0x36,
12471 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
12472 0x03, 0x5c, 0x28, 0xfe,
12473 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
12474 0x05, 0x1f, 0xfe, 0x02,
12475 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
12476 0x01, 0x4b, 0x12, 0xfe,
12477 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
12478 0x12, 0x03, 0x45, 0x28,
12479 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
12480 0x43, 0x48, 0xc4, 0xcc,
12481 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
12482 0x6e, 0x41, 0x01, 0xb2,
12483 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
12484 0xfe, 0xcc, 0x15, 0x1d,
12485 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
12486 0x45, 0xc1, 0x0c, 0x45,
12487 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
12488 0xe2, 0x00, 0x27, 0xdb,
12489 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
12490 0xfe, 0x06, 0xf0, 0xfe,
12491 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
12492 0x16, 0x19, 0x01, 0x0b,
12493 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
12494 0xfe, 0x99, 0xa4, 0x01,
12495 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
12496 0x12, 0x08, 0x05, 0x1a,
12497 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
12498 0x0b, 0x16, 0x00, 0x01,
12499 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
12500 0xe2, 0x6c, 0x58, 0xbe,
12501 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
12502 0xfe, 0x09, 0x6f, 0xba,
12503 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
12504 0xfe, 0x54, 0x07, 0x1c,
12505 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
12506 0x07, 0x02, 0x24, 0x01,
12507 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
12508 0x2c, 0x90, 0xfe, 0xae,
12509 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
12510 0x37, 0x22, 0x20, 0x07,
12511 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
12512 0xfe, 0x06, 0x10, 0xfe,
12513 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
12514 0x37, 0x01, 0xb3, 0xb8,
12515 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
12516 0x50, 0xfe, 0x44, 0x51,
12517 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
12518 0x14, 0x5f, 0xfe, 0x0c,
12519 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
12520 0x14, 0x3e, 0xfe, 0x4a,
12521 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
12522 0x90, 0x0c, 0x60, 0x14,
12523 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
12524 0xfe, 0x44, 0x90, 0xfe,
12525 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
12526 0x0c, 0x5e, 0x14, 0x5f,
12527 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
12528 0x14, 0x3c, 0x21, 0x0c,
12529 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
12530 0x27, 0xdd, 0xfe, 0x9e,
12531 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
12532 0x9a, 0x08, 0xc6, 0xfe,
12533 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
12534 0x95, 0x86, 0x02, 0x24,
12535 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
12536 0x06, 0xfe, 0x10, 0x12,
12537 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
12538 0x1c, 0x02, 0xfe, 0x18,
12539 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
12540 0x2c, 0x1c, 0xfe, 0xaa,
12541 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
12542 0xde, 0x09, 0xfe, 0xb7,
12543 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
12544 0xfe, 0xf1, 0x18, 0xfe,
12545 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
12546 0x14, 0x59, 0xfe, 0x95,
12547 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
12548 0xfe, 0xf0, 0x08, 0xb5,
12549 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
12550 0x0b, 0xb6, 0xfe, 0xbf,
12551 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
12552 0x12, 0xc2, 0xfe, 0xd2,
12553 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
12554 0x06, 0x17, 0x85, 0xc5,
12555 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
12556 0x9d, 0x01, 0x36, 0x10,
12557 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
12558 0x98, 0x80, 0xfe, 0x19,
12559 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
12560 0xfe, 0x44, 0x54, 0xbe,
12561 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
12562 0x02, 0x4a, 0x08, 0x05,
12563 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
12564 0x9c, 0x3c, 0xfe, 0x6c,
12565 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
12566 0x3b, 0x40, 0x03, 0x49,
12567 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
12568 0x8f, 0xfe, 0xe3, 0x54,
12569 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
12570 0xda, 0x09, 0xfe, 0x8b,
12571 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
12572 0x0a, 0x3a, 0x49, 0x3b,
12573 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
12574 0xad, 0xfe, 0x01, 0x59,
12575 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
12576 0x49, 0x8f, 0xfe, 0xe3,
12577 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
12578 0x4a, 0x3a, 0x49, 0x3b,
12579 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
12580 0x02, 0x4a, 0x08, 0x05,
12581 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
12582 0xb7, 0xfe, 0x03, 0xa1,
12583 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12584 0xfe, 0x86, 0x91, 0x6a,
12585 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12586 0x61, 0x0c, 0x7f, 0x14,
12587 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12588 0x9b, 0x2e, 0x9c, 0x3c,
12589 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12590 0xfa, 0x3c, 0x01, 0xef,
12591 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12592 0xe4, 0x08, 0x05, 0x1f,
12593 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12594 0x03, 0x5e, 0x29, 0x5f,
12595 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12596 0xf4, 0x09, 0x08, 0x05,
12597 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12598 0x81, 0x50, 0xfe, 0x10,
12599 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12600 0x08, 0x09, 0x12, 0xa6,
12601 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12602 0x08, 0x09, 0xfe, 0x0c,
12603 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12604 0x08, 0x05, 0x0a, 0xfe,
12605 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12606 0xf0, 0xe2, 0x15, 0x7e,
12607 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12608 0x57, 0x3d, 0xfe, 0xed,
12609 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12610 0x00, 0xff, 0x35, 0xfe,
12611 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12612 0x1e, 0x19, 0x8a, 0x03,
12613 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12614 0xfe, 0xd1, 0xf0, 0xfe,
12615 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12616 0x10, 0xfe, 0xce, 0xf0,
12617 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12618 0x10, 0xfe, 0x22, 0x00,
12619 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12620 0x02, 0x65, 0xfe, 0xd0,
12621 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12622 0x0b, 0x10, 0x58, 0xfe,
12623 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12624 0x12, 0x00, 0x2c, 0x0f,
12625 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12626 0x0c, 0xbc, 0x17, 0x34,
12627 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12628 0x0c, 0x1c, 0x34, 0x94,
12629 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12630 0x4b, 0xfe, 0xdb, 0x10,
12631 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12632 0x89, 0xf0, 0x24, 0x33,
12633 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12634 0x33, 0x31, 0xdf, 0xbc,
12635 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12636 0x17, 0xfe, 0x2c, 0x0d,
12637 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12638 0x12, 0x55, 0xfe, 0x28,
12639 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12640 0x44, 0xfe, 0x28, 0x00,
12641 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12642 0x0f, 0x64, 0x12, 0x2f,
12643 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12644 0x0a, 0xfe, 0xb4, 0x10,
12645 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12646 0xfe, 0x34, 0x46, 0xac,
12647 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12648 0x37, 0x01, 0xf5, 0x01,
12649 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12650 0xfe, 0x2e, 0x03, 0x08,
12651 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12652 0x1a, 0xfe, 0x58, 0x12,
12653 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12654 0xfe, 0x50, 0x0d, 0xfe,
12655 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12656 0xfe, 0xa9, 0x10, 0x10,
12657 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12658 0xfe, 0x13, 0x00, 0xfe,
12659 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12660 0x24, 0x00, 0x8c, 0xb5,
12661 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12662 0xfe, 0x9d, 0x41, 0xfe,
12663 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12664 0xb4, 0x15, 0xfe, 0x31,
12665 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12666 0xec, 0xd0, 0xfc, 0x44,
12667 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12668 0x4b, 0x91, 0xfe, 0x75,
12669 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12670 0x0e, 0xfe, 0x44, 0x48,
12671 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12672 0xfe, 0x41, 0x58, 0x09,
12673 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12674 0x2e, 0x03, 0x09, 0x5d,
12675 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12676 0xce, 0x47, 0xfe, 0xad,
12677 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12678 0x59, 0x13, 0x9f, 0x13,
12679 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12680 0xe0, 0x0e, 0x0f, 0x06,
12681 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12682 0x3a, 0x01, 0x56, 0xfe,
12683 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12684 0x20, 0x4f, 0xfe, 0x05,
12685 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12686 0x48, 0xf4, 0x0d, 0xfe,
12687 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12688 0x15, 0x1a, 0x39, 0xa0,
12689 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12690 0x0c, 0xfe, 0x60, 0x01,
12691 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12692 0x06, 0x13, 0x2f, 0x12,
12693 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12694 0x22, 0x9f, 0xb7, 0x13,
12695 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12696 0xa0, 0xb4, 0xfe, 0xd9,
12697 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12698 0xc3, 0xfe, 0x03, 0xdc,
12699 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12700 0xfe, 0x00, 0xcc, 0x04,
12701 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12702 0xfe, 0x1c, 0x80, 0x07,
12703 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12704 0xfe, 0x0c, 0x90, 0xfe,
12705 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12706 0x0a, 0xfe, 0x3c, 0x50,
12707 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12708 0x16, 0x08, 0x05, 0x1b,
12709 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12710 0xfe, 0x2c, 0x13, 0x01,
12711 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12712 0x0c, 0xfe, 0x64, 0x01,
12713 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12714 0x80, 0x8d, 0xfe, 0x01,
12715 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12716 0x22, 0x20, 0xfb, 0x79,
12717 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12718 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012720 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12721 0xb2, 0x00, 0xfe, 0x09,
12722 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12723 0x45, 0x0f, 0x46, 0x52,
12724 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12725 0x0f, 0x44, 0x11, 0x0f,
12726 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12727 0x25, 0x11, 0x13, 0x20,
12728 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12729 0x56, 0xfe, 0xd6, 0xf0,
12730 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12731 0x18, 0x1c, 0x04, 0x42,
12732 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12733 0xf5, 0x13, 0x04, 0x01,
12734 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12735 0x13, 0x32, 0x07, 0x2f,
12736 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12737 0x41, 0x48, 0xfe, 0x45,
12738 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12739 0x07, 0x11, 0xac, 0x09,
12740 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12741 0x82, 0x4e, 0xfe, 0x14,
12742 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12743 0xfe, 0x01, 0xec, 0xa2,
12744 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12745 0x2a, 0x01, 0xe3, 0xfe,
12746 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12747 0xfe, 0x48, 0x12, 0x07,
12748 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12749 0xfe, 0x32, 0x12, 0x07,
12750 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12751 0x1f, 0xfe, 0x12, 0x12,
12752 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12753 0x94, 0x4b, 0x04, 0x2d,
12754 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12755 0x32, 0x07, 0xa6, 0xfe,
12756 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12757 0x5a, 0xfe, 0x72, 0x12,
12758 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12759 0xfe, 0x26, 0x13, 0x03,
12760 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12761 0x0c, 0x7f, 0x0c, 0x80,
12762 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12763 0x3c, 0xfe, 0x04, 0x55,
12764 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12765 0x91, 0x10, 0x03, 0x3f,
12766 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12767 0x88, 0x9b, 0x2e, 0x9c,
12768 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12769 0x56, 0x0c, 0x5e, 0x14,
12770 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12771 0x03, 0x60, 0x29, 0x61,
12772 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12773 0x50, 0xfe, 0xc6, 0x50,
12774 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12775 0x29, 0x3e, 0xfe, 0x40,
12776 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12777 0x2d, 0x01, 0x0b, 0x1d,
12778 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12779 0x72, 0x01, 0xaf, 0x1e,
12780 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12781 0x0a, 0x55, 0x35, 0xfe,
12782 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12783 0x02, 0x72, 0xfe, 0x19,
12784 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12785 0x1d, 0xe8, 0x33, 0x31,
12786 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12787 0x0b, 0x1c, 0x34, 0x1d,
12788 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12789 0x33, 0x31, 0xfe, 0xe8,
12790 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12791 0x05, 0x1f, 0x35, 0xa9,
12792 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12793 0x14, 0x01, 0xaf, 0x8c,
12794 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12795 0x03, 0x45, 0x28, 0x35,
12796 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12797 0x03, 0x5c, 0xc1, 0x0c,
12798 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12799 0x89, 0x01, 0x0b, 0x1c,
12800 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12801 0xfe, 0x42, 0x58, 0xf1,
12802 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12803 0xf4, 0x06, 0xea, 0x32,
12804 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12805 0x01, 0x0b, 0x26, 0x89,
12806 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12807 0x26, 0xfe, 0xd4, 0x13,
12808 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12809 0x13, 0x1c, 0xfe, 0xd0,
12810 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12811 0x0f, 0x71, 0xff, 0x02,
12812 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12813 0x00, 0x5c, 0x04, 0x0f,
12814 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12815 0xfe, 0x00, 0x5c, 0x04,
12816 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12817 0x02, 0x00, 0x57, 0x52,
12818 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12819 0x87, 0x04, 0xfe, 0x03,
12820 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12821 0xfe, 0x00, 0x7d, 0xfe,
12822 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12823 0x14, 0x5f, 0x57, 0x3f,
12824 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12825 0x5a, 0x8d, 0x04, 0x01,
12826 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12827 0xfe, 0x96, 0x15, 0x33,
12828 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12829 0x0a, 0xfe, 0xc1, 0x59,
12830 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12831 0x21, 0x69, 0x1a, 0xee,
12832 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12833 0x30, 0xfe, 0x78, 0x10,
12834 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12835 0x98, 0xfe, 0x30, 0x00,
12836 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12837 0x98, 0xfe, 0x64, 0x00,
12838 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12839 0x10, 0x69, 0x06, 0xfe,
12840 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12841 0x18, 0x59, 0x0f, 0x06,
12842 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12843 0x43, 0xf4, 0x9f, 0xfe,
12844 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12845 0x9e, 0xfe, 0xf3, 0x10,
12846 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12847 0x17, 0xfe, 0x4d, 0xe4,
12848 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12849 0x17, 0xfe, 0x4d, 0xe4,
12850 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12851 0xf4, 0x00, 0xe9, 0x91,
12852 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12853 0x04, 0x16, 0x06, 0x01,
12854 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12855 0x0b, 0x26, 0xf3, 0x76,
12856 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12857 0x16, 0x19, 0x01, 0x0b,
12858 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12859 0x0b, 0x26, 0xb1, 0x76,
12860 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12861 0xfe, 0x48, 0x13, 0xb8,
12862 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12863 0xec, 0xfe, 0x27, 0x01,
12864 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12865 0x07, 0xfe, 0xe3, 0x00,
12866 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12867 0x22, 0xd4, 0x07, 0x06,
12868 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12869 0x07, 0x11, 0xae, 0x09,
12870 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12871 0x0e, 0x8e, 0xfe, 0x80,
12872 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12873 0x09, 0x48, 0x01, 0x0e,
12874 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12875 0x80, 0xfe, 0x80, 0x4c,
12876 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12877 0x09, 0x5d, 0x01, 0x87,
12878 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12879 0x19, 0xde, 0xfe, 0x24,
12880 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12881 0x17, 0xad, 0x9a, 0x1b,
12882 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12883 0x16, 0xfe, 0xda, 0x10,
12884 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12885 0x18, 0x58, 0x03, 0xfe,
12886 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12887 0xf4, 0x06, 0xfe, 0x3c,
12888 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12889 0x97, 0xfe, 0x38, 0x17,
12890 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12891 0x10, 0x18, 0x11, 0x75,
12892 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12893 0x2e, 0x97, 0xfe, 0x5a,
12894 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12895 0xfe, 0x98, 0xe7, 0x00,
12896 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12897 0xfe, 0x30, 0xbc, 0xfe,
12898 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12899 0xcb, 0x97, 0xfe, 0x92,
12900 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12901 0x42, 0x10, 0xfe, 0x02,
12902 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12903 0x03, 0xa1, 0xfe, 0x1d,
12904 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12905 0x9a, 0x5b, 0x41, 0xfe,
12906 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12907 0x11, 0x12, 0xfe, 0xdd,
12908 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12909 0x17, 0x15, 0x06, 0x39,
12910 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12911 0xfe, 0x7e, 0x18, 0x1e,
12912 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12913 0x12, 0xfe, 0xe1, 0x10,
12914 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12915 0x13, 0x42, 0x92, 0x09,
12916 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12917 0xf0, 0xfe, 0x00, 0xcc,
12918 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12919 0x0e, 0xfe, 0x80, 0x4c,
12920 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12921 0x24, 0x12, 0xfe, 0x14,
12922 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12923 0xe7, 0x0a, 0x10, 0xfe,
12924 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12925 0x08, 0x54, 0x1b, 0x37,
12926 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12927 0x90, 0x3a, 0xce, 0x3b,
12928 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
12929 0x13, 0xa3, 0x04, 0x09,
12930 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
12931 0x44, 0x17, 0xfe, 0xe8,
12932 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
12933 0x5d, 0x01, 0xa8, 0x09,
12934 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
12935 0x1c, 0x19, 0x03, 0xfe,
12936 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
12937 0x6b, 0xfe, 0x2e, 0x19,
12938 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
12939 0xfe, 0x0b, 0x00, 0x6b,
12940 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
12941 0x08, 0x10, 0x03, 0xfe,
12942 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
12943 0x04, 0x68, 0x54, 0xe7,
12944 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
12945 0x1a, 0xf4, 0xfe, 0x00,
12946 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
12947 0x04, 0x07, 0x7e, 0xfe,
12948 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12949 0x07, 0x1a, 0xfe, 0x5a,
12950 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
12951 0x25, 0x6d, 0xe5, 0x07,
12952 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
12953 0xa9, 0xb8, 0x04, 0x15,
12954 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
12955 0x40, 0x5c, 0x04, 0x1c,
12956 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
12957 0xf7, 0xfe, 0x82, 0xf0,
12958 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012959};
12960
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012961static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
12962static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012963
12964/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012965static unsigned char _adv_asc38C1600_buf[] = {
12966 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
12967 0x18, 0xe4, 0x01, 0x00,
12968 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
12969 0x07, 0x17, 0xc0, 0x5f,
12970 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
12971 0x85, 0xf0, 0x86, 0xf0,
12972 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
12973 0x98, 0x57, 0x01, 0xe6,
12974 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
12975 0x38, 0x54, 0x32, 0xf0,
12976 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
12977 0x00, 0xe6, 0xb1, 0xf0,
12978 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
12979 0x06, 0x13, 0x0c, 0x1c,
12980 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
12981 0xb9, 0x54, 0x00, 0x80,
12982 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
12983 0x03, 0xe6, 0x01, 0xea,
12984 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
12985 0x04, 0x13, 0xbb, 0x55,
12986 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
12987 0xbb, 0x00, 0xc0, 0x00,
12988 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
12989 0x4c, 0x1c, 0x4e, 0x1c,
12990 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
12991 0x24, 0x01, 0x3c, 0x01,
12992 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
12993 0x78, 0x01, 0x7c, 0x01,
12994 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
12995 0x6e, 0x1e, 0x02, 0x48,
12996 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
12997 0x03, 0xfc, 0x06, 0x00,
12998 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
12999 0x30, 0x1c, 0x38, 0x1c,
13000 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
13001 0x5d, 0xf0, 0xa7, 0xf0,
13002 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
13003 0x33, 0x00, 0x34, 0x00,
13004 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
13005 0x79, 0x01, 0x3c, 0x09,
13006 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
13007 0x40, 0x16, 0x50, 0x16,
13008 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
13009 0x05, 0xf0, 0x09, 0xf0,
13010 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
13011 0x9c, 0x00, 0xa4, 0x00,
13012 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
13013 0xe9, 0x09, 0x5c, 0x0c,
13014 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
13015 0x42, 0x1d, 0x08, 0x44,
13016 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
13017 0x83, 0x55, 0x83, 0x59,
13018 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
13019 0x4b, 0xf4, 0x04, 0xf8,
13020 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
13021 0xa8, 0x00, 0xaa, 0x00,
13022 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
13023 0x7a, 0x01, 0x82, 0x01,
13024 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
13025 0x68, 0x08, 0x10, 0x0d,
13026 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
13027 0xf3, 0x10, 0x06, 0x12,
13028 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
13029 0xf0, 0x35, 0x05, 0xfe,
13030 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
13031 0xfe, 0x88, 0x01, 0xff,
13032 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
13033 0x00, 0xfe, 0x57, 0x24,
13034 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
13035 0x00, 0x00, 0xff, 0x08,
13036 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
13037 0xff, 0xff, 0xff, 0x13,
13038 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
13039 0xfe, 0x04, 0xf7, 0xe8,
13040 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
13041 0x0d, 0x51, 0x37, 0xfe,
13042 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
13043 0xfe, 0xf8, 0x01, 0xfe,
13044 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
13045 0x05, 0xfe, 0x08, 0x0f,
13046 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
13047 0x28, 0x1c, 0x03, 0xfe,
13048 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
13049 0x48, 0xf0, 0xfe, 0x90,
13050 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
13051 0x02, 0xfe, 0x46, 0xf0,
13052 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
13053 0xfe, 0x4e, 0x02, 0xfe,
13054 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
13055 0x0d, 0xa2, 0x1c, 0x07,
13056 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
13057 0x1c, 0xf5, 0xfe, 0x1e,
13058 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
13059 0xde, 0x0a, 0x81, 0x01,
13060 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
13061 0x81, 0x01, 0x5c, 0xfe,
13062 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
13063 0xfe, 0x58, 0x1c, 0x1c,
13064 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
13065 0x2b, 0xfe, 0x9e, 0x02,
13066 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
13067 0x00, 0x47, 0xb8, 0x01,
13068 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
13069 0x1a, 0x31, 0xfe, 0x69,
13070 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
13071 0x1e, 0x1e, 0x20, 0x2c,
13072 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
13073 0x44, 0x15, 0x56, 0x51,
13074 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
13075 0x01, 0x18, 0x09, 0x00,
13076 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
13077 0x18, 0xfe, 0xc8, 0x54,
13078 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
13079 0xfe, 0x02, 0xe8, 0x30,
13080 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
13081 0xfe, 0xe4, 0x01, 0xfe,
13082 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
13083 0x26, 0xf0, 0xfe, 0x66,
13084 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
13085 0xef, 0x10, 0xfe, 0x9f,
13086 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
13087 0x70, 0x37, 0xfe, 0x48,
13088 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
13089 0x21, 0xb9, 0xc7, 0x20,
13090 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
13091 0xe1, 0x2a, 0xeb, 0xfe,
13092 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
13093 0x15, 0xfe, 0xe4, 0x00,
13094 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
13095 0xfe, 0x06, 0xf0, 0xfe,
13096 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
13097 0x03, 0x81, 0x1e, 0x1b,
13098 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
13099 0xea, 0xfe, 0x46, 0x1c,
13100 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
13101 0xfe, 0x48, 0x1c, 0x75,
13102 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
13103 0xe1, 0x01, 0x18, 0x77,
13104 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
13105 0x8f, 0xfe, 0x70, 0x02,
13106 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
13107 0x16, 0xfe, 0x4a, 0x04,
13108 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
13109 0x02, 0x00, 0x10, 0x01,
13110 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
13111 0xee, 0xfe, 0x4c, 0x44,
13112 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
13113 0x7b, 0xec, 0x60, 0x8d,
13114 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
13115 0x0c, 0x06, 0x28, 0xfe,
13116 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
13117 0x13, 0x34, 0xfe, 0x4c,
13118 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
13119 0x13, 0x01, 0x0c, 0x06,
13120 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
13121 0x28, 0xf9, 0x1f, 0x7f,
13122 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
13123 0xfe, 0xa4, 0x0e, 0x05,
13124 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
13125 0x9c, 0x93, 0x3a, 0x0b,
13126 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
13127 0x7d, 0x1d, 0xfe, 0x46,
13128 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
13129 0xfe, 0x87, 0x83, 0xfe,
13130 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
13131 0x13, 0x0f, 0xfe, 0x20,
13132 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
13133 0x12, 0x01, 0x38, 0x06,
13134 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
13135 0x05, 0xd0, 0x54, 0x01,
13136 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
13137 0x50, 0x12, 0x5e, 0xff,
13138 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
13139 0x00, 0x10, 0x2f, 0xfe,
13140 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
13141 0x38, 0xfe, 0x4a, 0xf0,
13142 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
13143 0x21, 0x00, 0xf1, 0x2e,
13144 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
13145 0x10, 0x2f, 0xfe, 0xd0,
13146 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
13147 0x1c, 0x00, 0x4d, 0x01,
13148 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
13149 0x28, 0xfe, 0x24, 0x12,
13150 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
13151 0x0d, 0x00, 0x01, 0x42,
13152 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
13153 0x03, 0xb6, 0x1e, 0xfe,
13154 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
13155 0xfe, 0x72, 0x06, 0x0a,
13156 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
13157 0x19, 0x16, 0xfe, 0x68,
13158 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
13159 0x03, 0x9a, 0x1e, 0xfe,
13160 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
13161 0x48, 0xfe, 0x92, 0x06,
13162 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
13163 0x58, 0xff, 0x02, 0x00,
13164 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
13165 0xfe, 0xea, 0x06, 0x01,
13166 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
13167 0xfe, 0xe0, 0x06, 0x15,
13168 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
13169 0x01, 0x84, 0xfe, 0xae,
13170 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
13171 0x1e, 0xfe, 0x1a, 0x12,
13172 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
13173 0x43, 0x48, 0x62, 0x80,
13174 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
13175 0x36, 0xfe, 0x02, 0xf6,
13176 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
13177 0xd0, 0x0d, 0x17, 0xfe,
13178 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
13179 0x9e, 0x15, 0x82, 0x01,
13180 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
13181 0x57, 0x10, 0xe6, 0x05,
13182 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
13183 0xfe, 0x9c, 0x32, 0x5f,
13184 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
13185 0xfe, 0x0a, 0xf0, 0xfe,
13186 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
13187 0xaf, 0xa0, 0x05, 0x29,
13188 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
13189 0x00, 0x01, 0x08, 0x14,
13190 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
13191 0x14, 0x00, 0x05, 0xfe,
13192 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
13193 0x12, 0xfe, 0x30, 0x13,
13194 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
13195 0x01, 0x08, 0x14, 0x00,
13196 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
13197 0x78, 0x4f, 0x0f, 0xfe,
13198 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
13199 0x28, 0x48, 0xfe, 0x6c,
13200 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
13201 0x12, 0x53, 0x63, 0x4e,
13202 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
13203 0x6c, 0x08, 0xaf, 0xa0,
13204 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
13205 0x05, 0xed, 0xfe, 0x9c,
13206 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
13207 0x1e, 0xfe, 0x99, 0x58,
13208 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
13209 0x22, 0x6b, 0x01, 0x0c,
13210 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
13211 0x1e, 0x47, 0x2c, 0x7a,
13212 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
13213 0x01, 0x0c, 0x61, 0x65,
13214 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
13215 0x16, 0xfe, 0x08, 0x50,
13216 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
13217 0x01, 0xfe, 0xce, 0x1e,
13218 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
13219 0x01, 0xfe, 0xfe, 0x1e,
13220 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
13221 0x10, 0x01, 0x0c, 0x06,
13222 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
13223 0x10, 0x6a, 0x22, 0x6b,
13224 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
13225 0xfe, 0x9f, 0x83, 0x33,
13226 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
13227 0x3a, 0x0b, 0xfe, 0xc6,
13228 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
13229 0x01, 0xfe, 0xce, 0x1e,
13230 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
13231 0x04, 0xfe, 0xc0, 0x93,
13232 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
13233 0x10, 0x4b, 0x22, 0x4c,
13234 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
13235 0x4e, 0x11, 0x2f, 0xfe,
13236 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
13237 0x3c, 0x37, 0x88, 0xf5,
13238 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
13239 0xd3, 0xfe, 0x42, 0x0a,
13240 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
13241 0x05, 0x29, 0x01, 0x41,
13242 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
13243 0xfe, 0x14, 0x12, 0x01,
13244 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
13245 0x2e, 0x1c, 0x05, 0xfe,
13246 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
13247 0xfe, 0x2c, 0x1c, 0xfe,
13248 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
13249 0x92, 0x10, 0xc4, 0xf6,
13250 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
13251 0xe7, 0x10, 0xfe, 0x2b,
13252 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
13253 0xac, 0xfe, 0xd2, 0xf0,
13254 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
13255 0x1b, 0xbf, 0xd4, 0x5b,
13256 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
13257 0x5e, 0x32, 0x1f, 0x7f,
13258 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
13259 0x05, 0x70, 0xfe, 0x74,
13260 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
13261 0x0f, 0x4d, 0x01, 0xfe,
13262 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
13263 0x0d, 0x2b, 0xfe, 0xe2,
13264 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
13265 0xfe, 0x88, 0x13, 0x21,
13266 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
13267 0x83, 0x83, 0xfe, 0xc9,
13268 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
13269 0x91, 0x04, 0xfe, 0x84,
13270 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
13271 0xfe, 0xcb, 0x57, 0x0b,
13272 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
13273 0x6a, 0x3b, 0x6b, 0x10,
13274 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
13275 0x20, 0x6e, 0xdb, 0x64,
13276 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
13277 0xfe, 0x04, 0xfa, 0x64,
13278 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
13279 0x10, 0x98, 0x91, 0x6c,
13280 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
13281 0x4b, 0x7e, 0x4c, 0x01,
13282 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
13283 0x58, 0xfe, 0x91, 0x58,
13284 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
13285 0x1b, 0x40, 0x01, 0x0c,
13286 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
13287 0xfe, 0x10, 0x90, 0x04,
13288 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
13289 0x79, 0x0b, 0x0e, 0xfe,
13290 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
13291 0x01, 0x0c, 0x06, 0x0d,
13292 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
13293 0x0c, 0x58, 0xfe, 0x8d,
13294 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
13295 0x83, 0x33, 0x0b, 0x0e,
13296 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
13297 0x19, 0xfe, 0x19, 0x41,
13298 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
13299 0x19, 0xfe, 0x44, 0x00,
13300 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
13301 0x4c, 0xfe, 0x0c, 0x51,
13302 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
13303 0x76, 0x10, 0xac, 0xfe,
13304 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
13305 0xe3, 0x23, 0x07, 0xfe,
13306 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
13307 0xcc, 0x0c, 0x1f, 0x92,
13308 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
13309 0x0c, 0xfe, 0x3e, 0x10,
13310 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
13311 0xfe, 0xcb, 0xf0, 0xfe,
13312 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
13313 0xf4, 0x0c, 0x19, 0x94,
13314 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
13315 0xfe, 0xcc, 0xf0, 0xef,
13316 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
13317 0x4e, 0x11, 0x2f, 0xfe,
13318 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
13319 0x3c, 0x37, 0x88, 0xf5,
13320 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
13321 0x2f, 0xfe, 0x3e, 0x0d,
13322 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
13323 0xd2, 0x9f, 0xd3, 0x9f,
13324 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
13325 0xc5, 0x75, 0xd7, 0x99,
13326 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
13327 0x9c, 0x2f, 0xfe, 0x8c,
13328 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
13329 0x42, 0x00, 0x05, 0x70,
13330 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
13331 0x0d, 0xfe, 0x44, 0x13,
13332 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
13333 0xfe, 0xda, 0x0e, 0x0a,
13334 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
13335 0x10, 0x01, 0xfe, 0xf4,
13336 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
13337 0x15, 0x56, 0x01, 0x85,
13338 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
13339 0xcc, 0x10, 0x01, 0xa7,
13340 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
13341 0xfe, 0x99, 0x83, 0xfe,
13342 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
13343 0x43, 0x00, 0xfe, 0xa2,
13344 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
13345 0x00, 0x1d, 0x40, 0x15,
13346 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
13347 0xfe, 0x3a, 0x03, 0x01,
13348 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
13349 0x76, 0x06, 0x12, 0xfe,
13350 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
13351 0xfe, 0x9d, 0xf0, 0xfe,
13352 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
13353 0x0c, 0x61, 0x12, 0x44,
13354 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
13355 0xfe, 0x2e, 0x10, 0x19,
13356 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
13357 0xfe, 0x41, 0x00, 0xa2,
13358 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
13359 0xea, 0x4f, 0xfe, 0x04,
13360 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
13361 0x35, 0xfe, 0x12, 0x1c,
13362 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
13363 0xfe, 0xd4, 0x11, 0x05,
13364 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
13365 0xce, 0x45, 0x31, 0x51,
13366 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
13367 0x67, 0xfe, 0x98, 0x56,
13368 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
13369 0x0c, 0x06, 0x28, 0xfe,
13370 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
13371 0xfe, 0xfa, 0x14, 0xfe,
13372 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
13373 0xfe, 0xe0, 0x14, 0xfe,
13374 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
13375 0xfe, 0xad, 0x13, 0x05,
13376 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
13377 0xe7, 0xfe, 0x08, 0x1c,
13378 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
13379 0x48, 0x55, 0xa5, 0x3b,
13380 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
13381 0xf0, 0x1a, 0x03, 0xfe,
13382 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
13383 0xec, 0xe7, 0x53, 0x00,
13384 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
13385 0x01, 0xfe, 0x62, 0x1b,
13386 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
13387 0xea, 0xe7, 0x53, 0x92,
13388 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
13389 0xfe, 0x38, 0x01, 0x23,
13390 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
13391 0x01, 0x01, 0xfe, 0x1e,
13392 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
13393 0x26, 0x02, 0x21, 0x96,
13394 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
13395 0xc3, 0xfe, 0xe1, 0x10,
13396 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
13397 0xfe, 0x03, 0xdc, 0xfe,
13398 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
13399 0x00, 0xcc, 0x02, 0xfe,
13400 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
13401 0x0f, 0xfe, 0x1c, 0x80,
13402 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
13403 0x0f, 0xfe, 0x1e, 0x80,
13404 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
13405 0x1d, 0x80, 0x04, 0xfe,
13406 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
13407 0x1e, 0xac, 0xfe, 0x14,
13408 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
13409 0x1f, 0xfe, 0x30, 0xf4,
13410 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
13411 0x56, 0xfb, 0x01, 0xfe,
13412 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
13413 0xfe, 0x00, 0x1d, 0x15,
13414 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
13415 0x22, 0x1b, 0xfe, 0x1e,
13416 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
13417 0x96, 0x90, 0x04, 0xfe,
13418 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
13419 0x01, 0x01, 0x0c, 0x06,
13420 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
13421 0x0e, 0x77, 0xfe, 0x01,
13422 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
13423 0x21, 0x2c, 0xfe, 0x00,
13424 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
13425 0x06, 0x58, 0x03, 0xfe,
13426 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
13427 0x03, 0xfe, 0xb2, 0x00,
13428 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
13429 0x66, 0x10, 0x55, 0x10,
13430 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
13431 0x54, 0x2b, 0xfe, 0x88,
13432 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
13433 0x91, 0x54, 0x2b, 0xfe,
13434 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
13435 0x00, 0x40, 0x8d, 0x2c,
13436 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
13437 0x12, 0x1c, 0x75, 0xfe,
13438 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
13439 0x14, 0xfe, 0x0e, 0x47,
13440 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
13441 0xa7, 0x90, 0x34, 0x60,
13442 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
13443 0x09, 0x56, 0xfe, 0x34,
13444 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
13445 0xfe, 0x45, 0x48, 0x01,
13446 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
13447 0x09, 0x1a, 0xa5, 0x0a,
13448 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
13449 0xfe, 0x14, 0x56, 0xfe,
13450 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
13451 0xec, 0xb8, 0xfe, 0x9e,
13452 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
13453 0xf4, 0xfe, 0xdd, 0x10,
13454 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
13455 0x12, 0x09, 0x0d, 0xfe,
13456 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
13457 0x13, 0x09, 0xfe, 0x23,
13458 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
13459 0x24, 0xfe, 0x12, 0x12,
13460 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
13461 0xae, 0x41, 0x02, 0x32,
13462 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
13463 0x35, 0x32, 0x01, 0x43,
13464 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
13465 0x13, 0x01, 0x0c, 0x06,
13466 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
13467 0xe5, 0x55, 0xb0, 0xfe,
13468 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
13469 0xfe, 0xb6, 0x0e, 0x10,
13470 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
13471 0x88, 0x20, 0x6e, 0x01,
13472 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
13473 0x55, 0xfe, 0x04, 0xfa,
13474 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
13475 0xfe, 0x40, 0x56, 0xfe,
13476 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
13477 0x44, 0x55, 0xfe, 0xe5,
13478 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
13479 0x68, 0x22, 0x69, 0x01,
13480 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
13481 0x6b, 0xfe, 0x2c, 0x50,
13482 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
13483 0x50, 0x03, 0x68, 0x3b,
13484 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
13485 0x40, 0x50, 0xfe, 0xc2,
13486 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
13487 0x16, 0x3d, 0x27, 0x25,
13488 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
13489 0xa6, 0x23, 0x3f, 0x1b,
13490 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
13491 0xfe, 0x0a, 0x55, 0x31,
13492 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
13493 0x51, 0x05, 0x72, 0x01,
13494 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
13495 0x2a, 0x3c, 0x16, 0xc0,
13496 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
13497 0xfe, 0x66, 0x15, 0x05,
13498 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
13499 0x2b, 0x3d, 0x01, 0x08,
13500 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
13501 0xb6, 0x1e, 0x83, 0x01,
13502 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
13503 0x07, 0x90, 0x3f, 0x01,
13504 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
13505 0x01, 0x43, 0x09, 0x82,
13506 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
13507 0x05, 0x72, 0xfe, 0xc0,
13508 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
13509 0x32, 0x01, 0x08, 0x17,
13510 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
13511 0x3d, 0x27, 0x25, 0xbd,
13512 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
13513 0xe8, 0x14, 0x01, 0xa6,
13514 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
13515 0x0e, 0x12, 0x01, 0x43,
13516 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
13517 0x01, 0x08, 0x17, 0x73,
13518 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
13519 0x27, 0x25, 0xbd, 0x09,
13520 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
13521 0xb6, 0x14, 0x86, 0xa8,
13522 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
13523 0x82, 0x4e, 0x05, 0x72,
13524 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
13525 0xfe, 0xc0, 0x19, 0x05,
13526 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
13527 0xcc, 0x01, 0x08, 0x26,
13528 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
13529 0xcc, 0x15, 0x5e, 0x32,
13530 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
13531 0xad, 0x23, 0xfe, 0xff,
13532 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
13533 0x00, 0x57, 0x52, 0xad,
13534 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
13535 0x02, 0x00, 0x57, 0x52,
13536 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
13537 0x02, 0x13, 0x58, 0xff,
13538 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
13539 0x5c, 0x0a, 0x55, 0x01,
13540 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
13541 0xff, 0x03, 0x00, 0x54,
13542 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
13543 0x7c, 0x3a, 0x0b, 0x0e,
13544 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
13545 0xfe, 0x1a, 0xf7, 0x00,
13546 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
13547 0xda, 0x6d, 0x02, 0xfe,
13548 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
13549 0x02, 0x01, 0xc6, 0xfe,
13550 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
13551 0x25, 0xbe, 0x01, 0x08,
13552 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
13553 0x03, 0x9a, 0x1e, 0xfe,
13554 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
13555 0x48, 0xfe, 0x08, 0x17,
13556 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
13557 0x17, 0x4d, 0x13, 0x07,
13558 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
13559 0xff, 0x02, 0x83, 0x55,
13560 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
13561 0x17, 0x1c, 0x63, 0x13,
13562 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
13563 0x00, 0xb0, 0xfe, 0x80,
13564 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
13565 0x53, 0x07, 0xfe, 0x60,
13566 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
13567 0x00, 0x1c, 0x95, 0x13,
13568 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
13569 0xfe, 0x43, 0xf4, 0x96,
13570 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
13571 0xf4, 0x94, 0xf6, 0x8b,
13572 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
13573 0xda, 0x17, 0x62, 0x49,
13574 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
13575 0x71, 0x50, 0x26, 0xfe,
13576 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
13577 0x58, 0x02, 0x50, 0x13,
13578 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
13579 0x25, 0xbe, 0xfe, 0x03,
13580 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
13581 0x0a, 0x01, 0x08, 0x16,
13582 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13583 0x01, 0x08, 0x16, 0xa9,
13584 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13585 0x08, 0x16, 0xa9, 0x27,
13586 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13587 0x01, 0x38, 0x06, 0x24,
13588 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13589 0x78, 0x03, 0x9a, 0x1e,
13590 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13591 0xfe, 0x40, 0x5a, 0x23,
13592 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13593 0x80, 0x48, 0xfe, 0xaa,
13594 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13595 0xfe, 0xac, 0x1d, 0xfe,
13596 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13597 0x43, 0x48, 0x2d, 0x93,
13598 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13599 0x36, 0xfe, 0x34, 0xf4,
13600 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13601 0x28, 0x10, 0xfe, 0xc0,
13602 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13603 0x18, 0x45, 0xfe, 0x1c,
13604 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13605 0x19, 0xfe, 0x04, 0xf4,
13606 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13607 0x21, 0xfe, 0x7f, 0x01,
13608 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13609 0x7e, 0x01, 0xfe, 0xc8,
13610 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13611 0x21, 0xfe, 0x81, 0x01,
13612 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13613 0x13, 0x0d, 0x02, 0x14,
13614 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13615 0xfe, 0x82, 0x19, 0x14,
13616 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13617 0x08, 0x02, 0x14, 0x07,
13618 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13619 0x01, 0x08, 0x17, 0xc1,
13620 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13621 0x08, 0x02, 0x50, 0x02,
13622 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13623 0x14, 0x12, 0x01, 0x08,
13624 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13625 0x08, 0x17, 0x74, 0xfe,
13626 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13627 0x74, 0x5f, 0xcc, 0x01,
13628 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13629 0xfe, 0x49, 0xf4, 0x00,
13630 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13631 0x02, 0x00, 0x10, 0x2f,
13632 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13633 0x16, 0xfe, 0x64, 0x1a,
13634 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13635 0x61, 0x07, 0x44, 0x02,
13636 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13637 0x13, 0x0a, 0x9d, 0x01,
13638 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13639 0xfe, 0x80, 0xe7, 0x1a,
13640 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13641 0x0a, 0x5a, 0x01, 0x18,
13642 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13643 0x7e, 0x1e, 0xfe, 0x80,
13644 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13645 0xfe, 0x80, 0x4c, 0x0a,
13646 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13647 0xfe, 0x19, 0xde, 0xfe,
13648 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13649 0x2a, 0x1c, 0xfa, 0xb3,
13650 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13651 0xf4, 0x1a, 0xfe, 0xfa,
13652 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13653 0xfe, 0x18, 0x58, 0x03,
13654 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13655 0xfe, 0x30, 0xf4, 0x07,
13656 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13657 0xf7, 0x24, 0xb1, 0xfe,
13658 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13659 0xfe, 0xba, 0x10, 0x1c,
13660 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13661 0x1d, 0xf7, 0x54, 0xb1,
13662 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13663 0xaf, 0x19, 0xfe, 0x98,
13664 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13665 0x1a, 0x87, 0x8b, 0x0f,
13666 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13667 0xfe, 0x32, 0x90, 0x04,
13668 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13669 0x7c, 0x12, 0xfe, 0x0f,
13670 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13671 0x31, 0x02, 0xc9, 0x2b,
13672 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13673 0x6a, 0xfe, 0x19, 0xfe,
13674 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13675 0x1b, 0xfe, 0x36, 0x14,
13676 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13677 0xfe, 0x80, 0xe7, 0x1a,
13678 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13679 0x30, 0xfe, 0x12, 0x45,
13680 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13681 0x39, 0xf0, 0x75, 0x26,
13682 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13683 0xe3, 0x23, 0x07, 0xfe,
13684 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13685 0x56, 0xfe, 0x3c, 0x13,
13686 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13687 0x01, 0x18, 0xcb, 0xfe,
13688 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13689 0xfe, 0x00, 0xcc, 0xcb,
13690 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13691 0xfe, 0x80, 0x4c, 0x01,
13692 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13693 0x12, 0xfe, 0x14, 0x56,
13694 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13695 0x0d, 0x19, 0xfe, 0x15,
13696 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13697 0x83, 0xfe, 0x18, 0x80,
13698 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13699 0x90, 0xfe, 0xba, 0x90,
13700 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13701 0x21, 0xb9, 0x88, 0x20,
13702 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13703 0x18, 0xfe, 0x49, 0x44,
13704 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13705 0x1a, 0xa4, 0x0a, 0x67,
13706 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13707 0x1d, 0x7b, 0xfe, 0x52,
13708 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13709 0x4e, 0xe4, 0xdd, 0x7b,
13710 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13711 0xfe, 0x4e, 0xe4, 0xfe,
13712 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13713 0xfe, 0x08, 0x10, 0x03,
13714 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13715 0x68, 0x54, 0xfe, 0xf1,
13716 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13717 0xfe, 0x1a, 0xf4, 0xfe,
13718 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13719 0x09, 0x92, 0xfe, 0x5a,
13720 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13721 0x5a, 0xf0, 0xfe, 0xc8,
13722 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13723 0x1a, 0x10, 0x09, 0x0d,
13724 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13725 0x1f, 0x93, 0x01, 0x42,
13726 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13727 0xfe, 0x14, 0xf0, 0x08,
13728 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13729 0xfe, 0x82, 0xf0, 0xfe,
13730 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13731 0x02, 0x0f, 0xfe, 0x18,
13732 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13733 0x80, 0x04, 0xfe, 0x82,
13734 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13735 0x83, 0x33, 0x0b, 0x0e,
13736 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13737 0x02, 0x0f, 0xfe, 0x04,
13738 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13739 0x80, 0x04, 0xfe, 0x80,
13740 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13741 0xfe, 0x99, 0x83, 0xfe,
13742 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13743 0x83, 0xfe, 0xce, 0x47,
13744 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13745 0x0b, 0x0e, 0x02, 0x0f,
13746 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13747 0xfe, 0x08, 0x90, 0x04,
13748 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13749 0xfe, 0x8a, 0x93, 0x79,
13750 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13751 0x0b, 0x0e, 0x02, 0x0f,
13752 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13753 0xfe, 0x3c, 0x90, 0x04,
13754 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13755 0x04, 0xfe, 0x83, 0x83,
13756 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013757};
13758
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013759static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13760static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013761
13762/* a_init.c */
13763/*
13764 * EEPROM Configuration.
13765 *
13766 * All drivers should use this structure to set the default EEPROM
13767 * configuration. The BIOS now uses this structure when it is built.
13768 * Additional structure information can be found in a_condor.h where
13769 * the structure is defined.
13770 *
13771 * The *_Field_IsChar structs are needed to correct for endianness.
13772 * These values are read from the board 16 bits at a time directly
13773 * into the structs. Because some fields are char, the values will be
13774 * in the wrong order. The *_Field_IsChar tells when to flip the
13775 * bytes. Data read and written to PCI memory is automatically swapped
13776 * on big-endian platforms so char fields read as words are actually being
13777 * unswapped on big-endian platforms.
13778 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013779static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = {
13780 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13781 0x0000, /* cfg_msw */
13782 0xFFFF, /* disc_enable */
13783 0xFFFF, /* wdtr_able */
13784 0xFFFF, /* sdtr_able */
13785 0xFFFF, /* start_motor */
13786 0xFFFF, /* tagqng_able */
13787 0xFFFF, /* bios_scan */
13788 0, /* scam_tolerant */
13789 7, /* adapter_scsi_id */
13790 0, /* bios_boot_delay */
13791 3, /* scsi_reset_delay */
13792 0, /* bios_id_lun */
13793 0, /* termination */
13794 0, /* reserved1 */
13795 0xFFE7, /* bios_ctrl */
13796 0xFFFF, /* ultra_able */
13797 0, /* reserved2 */
13798 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13799 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13800 0, /* dvc_cntl */
13801 0, /* bug_fix */
13802 0, /* serial_number_word1 */
13803 0, /* serial_number_word2 */
13804 0, /* serial_number_word3 */
13805 0, /* check_sum */
13806 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13807 , /* oem_name[16] */
13808 0, /* dvc_err_code */
13809 0, /* adv_err_code */
13810 0, /* adv_err_addr */
13811 0, /* saved_dvc_err_code */
13812 0, /* saved_adv_err_code */
13813 0, /* saved_adv_err_addr */
13814 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013815};
13816
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013817static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = {
13818 0, /* cfg_lsw */
13819 0, /* cfg_msw */
13820 0, /* -disc_enable */
13821 0, /* wdtr_able */
13822 0, /* sdtr_able */
13823 0, /* start_motor */
13824 0, /* tagqng_able */
13825 0, /* bios_scan */
13826 0, /* scam_tolerant */
13827 1, /* adapter_scsi_id */
13828 1, /* bios_boot_delay */
13829 1, /* scsi_reset_delay */
13830 1, /* bios_id_lun */
13831 1, /* termination */
13832 1, /* reserved1 */
13833 0, /* bios_ctrl */
13834 0, /* ultra_able */
13835 0, /* reserved2 */
13836 1, /* max_host_qng */
13837 1, /* max_dvc_qng */
13838 0, /* dvc_cntl */
13839 0, /* bug_fix */
13840 0, /* serial_number_word1 */
13841 0, /* serial_number_word2 */
13842 0, /* serial_number_word3 */
13843 0, /* check_sum */
13844 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13845 , /* oem_name[16] */
13846 0, /* dvc_err_code */
13847 0, /* adv_err_code */
13848 0, /* adv_err_addr */
13849 0, /* saved_dvc_err_code */
13850 0, /* saved_adv_err_code */
13851 0, /* saved_adv_err_addr */
13852 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013853};
13854
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013855static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = {
13856 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13857 0x0000, /* 01 cfg_msw */
13858 0xFFFF, /* 02 disc_enable */
13859 0xFFFF, /* 03 wdtr_able */
13860 0x4444, /* 04 sdtr_speed1 */
13861 0xFFFF, /* 05 start_motor */
13862 0xFFFF, /* 06 tagqng_able */
13863 0xFFFF, /* 07 bios_scan */
13864 0, /* 08 scam_tolerant */
13865 7, /* 09 adapter_scsi_id */
13866 0, /* bios_boot_delay */
13867 3, /* 10 scsi_reset_delay */
13868 0, /* bios_id_lun */
13869 0, /* 11 termination_se */
13870 0, /* termination_lvd */
13871 0xFFE7, /* 12 bios_ctrl */
13872 0x4444, /* 13 sdtr_speed2 */
13873 0x4444, /* 14 sdtr_speed3 */
13874 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13875 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13876 0, /* 16 dvc_cntl */
13877 0x4444, /* 17 sdtr_speed4 */
13878 0, /* 18 serial_number_word1 */
13879 0, /* 19 serial_number_word2 */
13880 0, /* 20 serial_number_word3 */
13881 0, /* 21 check_sum */
13882 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13883 , /* 22-29 oem_name[16] */
13884 0, /* 30 dvc_err_code */
13885 0, /* 31 adv_err_code */
13886 0, /* 32 adv_err_addr */
13887 0, /* 33 saved_dvc_err_code */
13888 0, /* 34 saved_adv_err_code */
13889 0, /* 35 saved_adv_err_addr */
13890 0, /* 36 reserved */
13891 0, /* 37 reserved */
13892 0, /* 38 reserved */
13893 0, /* 39 reserved */
13894 0, /* 40 reserved */
13895 0, /* 41 reserved */
13896 0, /* 42 reserved */
13897 0, /* 43 reserved */
13898 0, /* 44 reserved */
13899 0, /* 45 reserved */
13900 0, /* 46 reserved */
13901 0, /* 47 reserved */
13902 0, /* 48 reserved */
13903 0, /* 49 reserved */
13904 0, /* 50 reserved */
13905 0, /* 51 reserved */
13906 0, /* 52 reserved */
13907 0, /* 53 reserved */
13908 0, /* 54 reserved */
13909 0, /* 55 reserved */
13910 0, /* 56 cisptr_lsw */
13911 0, /* 57 cisprt_msw */
13912 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13913 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13914 0, /* 60 reserved */
13915 0, /* 61 reserved */
13916 0, /* 62 reserved */
13917 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013918};
13919
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013920static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = {
13921 0, /* 00 cfg_lsw */
13922 0, /* 01 cfg_msw */
13923 0, /* 02 disc_enable */
13924 0, /* 03 wdtr_able */
13925 0, /* 04 sdtr_speed1 */
13926 0, /* 05 start_motor */
13927 0, /* 06 tagqng_able */
13928 0, /* 07 bios_scan */
13929 0, /* 08 scam_tolerant */
13930 1, /* 09 adapter_scsi_id */
13931 1, /* bios_boot_delay */
13932 1, /* 10 scsi_reset_delay */
13933 1, /* bios_id_lun */
13934 1, /* 11 termination_se */
13935 1, /* termination_lvd */
13936 0, /* 12 bios_ctrl */
13937 0, /* 13 sdtr_speed2 */
13938 0, /* 14 sdtr_speed3 */
13939 1, /* 15 max_host_qng */
13940 1, /* max_dvc_qng */
13941 0, /* 16 dvc_cntl */
13942 0, /* 17 sdtr_speed4 */
13943 0, /* 18 serial_number_word1 */
13944 0, /* 19 serial_number_word2 */
13945 0, /* 20 serial_number_word3 */
13946 0, /* 21 check_sum */
13947 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13948 , /* 22-29 oem_name[16] */
13949 0, /* 30 dvc_err_code */
13950 0, /* 31 adv_err_code */
13951 0, /* 32 adv_err_addr */
13952 0, /* 33 saved_dvc_err_code */
13953 0, /* 34 saved_adv_err_code */
13954 0, /* 35 saved_adv_err_addr */
13955 0, /* 36 reserved */
13956 0, /* 37 reserved */
13957 0, /* 38 reserved */
13958 0, /* 39 reserved */
13959 0, /* 40 reserved */
13960 0, /* 41 reserved */
13961 0, /* 42 reserved */
13962 0, /* 43 reserved */
13963 0, /* 44 reserved */
13964 0, /* 45 reserved */
13965 0, /* 46 reserved */
13966 0, /* 47 reserved */
13967 0, /* 48 reserved */
13968 0, /* 49 reserved */
13969 0, /* 50 reserved */
13970 0, /* 51 reserved */
13971 0, /* 52 reserved */
13972 0, /* 53 reserved */
13973 0, /* 54 reserved */
13974 0, /* 55 reserved */
13975 0, /* 56 cisptr_lsw */
13976 0, /* 57 cisprt_msw */
13977 0, /* 58 subsysvid */
13978 0, /* 59 subsysid */
13979 0, /* 60 reserved */
13980 0, /* 61 reserved */
13981 0, /* 62 reserved */
13982 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013983};
13984
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013985static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = {
13986 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13987 0x0000, /* 01 cfg_msw */
13988 0xFFFF, /* 02 disc_enable */
13989 0xFFFF, /* 03 wdtr_able */
13990 0x5555, /* 04 sdtr_speed1 */
13991 0xFFFF, /* 05 start_motor */
13992 0xFFFF, /* 06 tagqng_able */
13993 0xFFFF, /* 07 bios_scan */
13994 0, /* 08 scam_tolerant */
13995 7, /* 09 adapter_scsi_id */
13996 0, /* bios_boot_delay */
13997 3, /* 10 scsi_reset_delay */
13998 0, /* bios_id_lun */
13999 0, /* 11 termination_se */
14000 0, /* termination_lvd */
14001 0xFFE7, /* 12 bios_ctrl */
14002 0x5555, /* 13 sdtr_speed2 */
14003 0x5555, /* 14 sdtr_speed3 */
14004 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
14005 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
14006 0, /* 16 dvc_cntl */
14007 0x5555, /* 17 sdtr_speed4 */
14008 0, /* 18 serial_number_word1 */
14009 0, /* 19 serial_number_word2 */
14010 0, /* 20 serial_number_word3 */
14011 0, /* 21 check_sum */
14012 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
14013 , /* 22-29 oem_name[16] */
14014 0, /* 30 dvc_err_code */
14015 0, /* 31 adv_err_code */
14016 0, /* 32 adv_err_addr */
14017 0, /* 33 saved_dvc_err_code */
14018 0, /* 34 saved_adv_err_code */
14019 0, /* 35 saved_adv_err_addr */
14020 0, /* 36 reserved */
14021 0, /* 37 reserved */
14022 0, /* 38 reserved */
14023 0, /* 39 reserved */
14024 0, /* 40 reserved */
14025 0, /* 41 reserved */
14026 0, /* 42 reserved */
14027 0, /* 43 reserved */
14028 0, /* 44 reserved */
14029 0, /* 45 reserved */
14030 0, /* 46 reserved */
14031 0, /* 47 reserved */
14032 0, /* 48 reserved */
14033 0, /* 49 reserved */
14034 0, /* 50 reserved */
14035 0, /* 51 reserved */
14036 0, /* 52 reserved */
14037 0, /* 53 reserved */
14038 0, /* 54 reserved */
14039 0, /* 55 reserved */
14040 0, /* 56 cisptr_lsw */
14041 0, /* 57 cisprt_msw */
14042 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
14043 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
14044 0, /* 60 reserved */
14045 0, /* 61 reserved */
14046 0, /* 62 reserved */
14047 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014048};
14049
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014050static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = {
14051 0, /* 00 cfg_lsw */
14052 0, /* 01 cfg_msw */
14053 0, /* 02 disc_enable */
14054 0, /* 03 wdtr_able */
14055 0, /* 04 sdtr_speed1 */
14056 0, /* 05 start_motor */
14057 0, /* 06 tagqng_able */
14058 0, /* 07 bios_scan */
14059 0, /* 08 scam_tolerant */
14060 1, /* 09 adapter_scsi_id */
14061 1, /* bios_boot_delay */
14062 1, /* 10 scsi_reset_delay */
14063 1, /* bios_id_lun */
14064 1, /* 11 termination_se */
14065 1, /* termination_lvd */
14066 0, /* 12 bios_ctrl */
14067 0, /* 13 sdtr_speed2 */
14068 0, /* 14 sdtr_speed3 */
14069 1, /* 15 max_host_qng */
14070 1, /* max_dvc_qng */
14071 0, /* 16 dvc_cntl */
14072 0, /* 17 sdtr_speed4 */
14073 0, /* 18 serial_number_word1 */
14074 0, /* 19 serial_number_word2 */
14075 0, /* 20 serial_number_word3 */
14076 0, /* 21 check_sum */
14077 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
14078 , /* 22-29 oem_name[16] */
14079 0, /* 30 dvc_err_code */
14080 0, /* 31 adv_err_code */
14081 0, /* 32 adv_err_addr */
14082 0, /* 33 saved_dvc_err_code */
14083 0, /* 34 saved_adv_err_code */
14084 0, /* 35 saved_adv_err_addr */
14085 0, /* 36 reserved */
14086 0, /* 37 reserved */
14087 0, /* 38 reserved */
14088 0, /* 39 reserved */
14089 0, /* 40 reserved */
14090 0, /* 41 reserved */
14091 0, /* 42 reserved */
14092 0, /* 43 reserved */
14093 0, /* 44 reserved */
14094 0, /* 45 reserved */
14095 0, /* 46 reserved */
14096 0, /* 47 reserved */
14097 0, /* 48 reserved */
14098 0, /* 49 reserved */
14099 0, /* 50 reserved */
14100 0, /* 51 reserved */
14101 0, /* 52 reserved */
14102 0, /* 53 reserved */
14103 0, /* 54 reserved */
14104 0, /* 55 reserved */
14105 0, /* 56 cisptr_lsw */
14106 0, /* 57 cisprt_msw */
14107 0, /* 58 subsysvid */
14108 0, /* 59 subsysid */
14109 0, /* 60 reserved */
14110 0, /* 61 reserved */
14111 0, /* 62 reserved */
14112 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014113};
14114
14115/*
14116 * Initialize the ADV_DVC_VAR structure.
14117 *
14118 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14119 *
14120 * For a non-fatal error return a warning code. If there are no warnings
14121 * then 0 is returned.
14122 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014123static int __init AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014124{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014125 ushort warn_code;
14126 AdvPortAddr iop_base;
14127 uchar pci_cmd_reg;
14128 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014129
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014130 warn_code = 0;
14131 asc_dvc->err_code = 0;
14132 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014133
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014134 /*
14135 * PCI Command Register
14136 *
14137 * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
14138 * I/O Space Control, Memory Space Control and Bus Master Control bits.
14139 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014140
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014141 if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
14142 AscPCIConfigCommandRegister))
14143 & AscPCICmdRegBits_BusMastering)
14144 != AscPCICmdRegBits_BusMastering) {
14145 pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014146
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014147 DvcAdvWritePCIConfigByte(asc_dvc,
14148 AscPCIConfigCommandRegister,
14149 pci_cmd_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014150
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014151 if (((DvcAdvReadPCIConfigByte
14152 (asc_dvc, AscPCIConfigCommandRegister))
14153 & AscPCICmdRegBits_BusMastering)
14154 != AscPCICmdRegBits_BusMastering) {
14155 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
14156 }
14157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014158
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014159 /*
14160 * PCI Latency Timer
14161 *
14162 * If the "latency timer" register is 0x20 or above, then we don't need
14163 * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
14164 * comes up less than 0x20).
14165 */
14166 if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
14167 DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer,
14168 0x20);
14169 if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) <
14170 0x20) {
14171 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
14172 }
14173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014174
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014175 /*
14176 * Save the state of the PCI Configuration Command Register
14177 * "Parity Error Response Control" Bit. If the bit is clear (0),
14178 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
14179 * DMA parity errors.
14180 */
14181 asc_dvc->cfg->control_flag = 0;
14182 if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
14183 & AscPCICmdRegBits_ParErrRespCtrl)) == 0) {
14184 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
14185 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014186
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014187 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
14188 ADV_LIB_VERSION_MINOR;
14189 asc_dvc->cfg->chip_version =
14190 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014191
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014192 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
14193 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
14194 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014195
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014196 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
14197 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
14198 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014199
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014200 /*
14201 * Reset the chip to start and allow register writes.
14202 */
14203 if (AdvFindSignature(iop_base) == 0) {
14204 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
14205 return ADV_ERROR;
14206 } else {
14207 /*
14208 * The caller must set 'chip_type' to a valid setting.
14209 */
14210 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
14211 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
14212 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
14213 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
14214 return ADV_ERROR;
14215 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014216
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014217 /*
14218 * Reset Chip.
14219 */
14220 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
14221 ADV_CTRL_REG_CMD_RESET);
14222 DvcSleepMilliSecond(100);
14223 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
14224 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014225
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014226 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14227 if ((status =
14228 AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) {
14229 return ADV_ERROR;
14230 }
14231 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
14232 if ((status =
14233 AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) {
14234 return ADV_ERROR;
14235 }
14236 } else {
14237 if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR) {
14238 return ADV_ERROR;
14239 }
14240 }
14241 warn_code |= status;
14242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014243
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014244 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014245}
14246
14247/*
14248 * Initialize the ASC-3550.
14249 *
14250 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14251 *
14252 * For a non-fatal error return a warning code. If there are no warnings
14253 * then 0 is returned.
14254 *
14255 * Needed after initialization for error recovery.
14256 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014257static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014258{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014259 AdvPortAddr iop_base;
14260 ushort warn_code;
14261 ADV_DCNT sum;
14262 int begin_addr;
14263 int end_addr;
14264 ushort code_sum;
14265 int word;
14266 int j;
14267 int adv_asc3550_expanded_size;
14268 ADV_CARR_T *carrp;
14269 ADV_DCNT contig_len;
14270 ADV_SDCNT buf_size;
14271 ADV_PADDR carr_paddr;
14272 int i;
14273 ushort scsi_cfg1;
14274 uchar tid;
14275 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14276 ushort wdtr_able = 0, sdtr_able, tagqng_able;
14277 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014278
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014279 /* If there is already an error, don't continue. */
14280 if (asc_dvc->err_code != 0) {
14281 return ADV_ERROR;
14282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014283
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014284 /*
14285 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
14286 */
14287 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
14288 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
14289 return ADV_ERROR;
14290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014291
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014292 warn_code = 0;
14293 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014294
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014295 /*
14296 * Save the RISC memory BIOS region before writing the microcode.
14297 * The BIOS may already be loaded and using its RISC LRAM region
14298 * so its region must be saved and restored.
14299 *
14300 * Note: This code makes the assumption, which is currently true,
14301 * that a chip reset does not clear RISC LRAM.
14302 */
14303 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14304 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14305 bios_mem[i]);
14306 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014307
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014308 /*
14309 * Save current per TID negotiated values.
14310 */
14311 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
14312 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014313
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014314 bios_version =
14315 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
14316 major = (bios_version >> 12) & 0xF;
14317 minor = (bios_version >> 8) & 0xF;
14318 if (major < 3 || (major == 3 && minor == 1)) {
14319 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
14320 AdvReadWordLram(iop_base, 0x120, wdtr_able);
14321 } else {
14322 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14323 }
14324 }
14325 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14326 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14327 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14328 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14329 max_cmd[tid]);
14330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014331
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014332 /*
14333 * Load the Microcode
14334 *
14335 * Write the microcode image to RISC memory starting at address 0.
14336 */
14337 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
14338 /* Assume the following compressed format of the microcode buffer:
14339 *
14340 * 254 word (508 byte) table indexed by byte code followed
14341 * by the following byte codes:
14342 *
14343 * 1-Byte Code:
14344 * 00: Emit word 0 in table.
14345 * 01: Emit word 1 in table.
14346 * .
14347 * FD: Emit word 253 in table.
14348 *
14349 * Multi-Byte Code:
14350 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14351 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14352 */
14353 word = 0;
14354 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
14355 if (_adv_asc3550_buf[i] == 0xff) {
14356 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
14357 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14358 _adv_asc3550_buf
14359 [i +
14360 3] << 8) |
14361 _adv_asc3550_buf
14362 [i + 2]));
14363 word++;
14364 }
14365 i += 3;
14366 } else if (_adv_asc3550_buf[i] == 0xfe) {
14367 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14368 _adv_asc3550_buf[i +
14369 2]
14370 << 8) |
14371 _adv_asc3550_buf[i +
14372 1]));
14373 i += 2;
14374 word++;
14375 } else {
14376 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14377 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
14378 word++;
14379 }
14380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014381
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014382 /*
14383 * Set 'word' for later use to clear the rest of memory and save
14384 * the expanded mcode size.
14385 */
14386 word *= 2;
14387 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014388
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014389 /*
14390 * Clear the rest of ASC-3550 Internal RAM (8KB).
14391 */
14392 for (; word < ADV_3550_MEMSIZE; word += 2) {
14393 AdvWriteWordAutoIncLram(iop_base, 0);
14394 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014395
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014396 /*
14397 * Verify the microcode checksum.
14398 */
14399 sum = 0;
14400 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014401
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014402 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
14403 sum += AdvReadWordAutoIncLram(iop_base);
14404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014405
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014406 if (sum != _adv_asc3550_chksum) {
14407 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14408 return ADV_ERROR;
14409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014410
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014411 /*
14412 * Restore the RISC memory BIOS region.
14413 */
14414 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14415 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14416 bios_mem[i]);
14417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014418
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014419 /*
14420 * Calculate and write the microcode code checksum to the microcode
14421 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14422 */
14423 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14424 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14425 code_sum = 0;
14426 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14427 for (word = begin_addr; word < end_addr; word += 2) {
14428 code_sum += AdvReadWordAutoIncLram(iop_base);
14429 }
14430 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014431
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014432 /*
14433 * Read and save microcode version and date.
14434 */
14435 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14436 asc_dvc->cfg->mcode_date);
14437 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14438 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014439
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014440 /*
14441 * Set the chip type to indicate the ASC3550.
14442 */
14443 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014444
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014445 /*
14446 * If the PCI Configuration Command Register "Parity Error Response
14447 * Control" Bit was clear (0), then set the microcode variable
14448 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14449 * to ignore DMA parity errors.
14450 */
14451 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14452 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14453 word |= CONTROL_FLAG_IGNORE_PERR;
14454 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014456
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014457 /*
14458 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
14459 * threshold of 128 bytes. This register is only accessible to the host.
14460 */
14461 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14462 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014463
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014464 /*
14465 * Microcode operating variables for WDTR, SDTR, and command tag
14466 * queuing will be set in AdvInquiryHandling() based on what a
14467 * device reports it is capable of in Inquiry byte 7.
14468 *
14469 * If SCSI Bus Resets have been disabled, then directly set
14470 * SDTR and WDTR from the EEPROM configuration. This will allow
14471 * the BIOS and warm boot to work without a SCSI bus hang on
14472 * the Inquiry caused by host and target mismatched DTR values.
14473 * Without the SCSI Bus Reset, before an Inquiry a device can't
14474 * be assumed to be in Asynchronous, Narrow mode.
14475 */
14476 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14477 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14478 asc_dvc->wdtr_able);
14479 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14480 asc_dvc->sdtr_able);
14481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014482
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014483 /*
14484 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
14485 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
14486 * bitmask. These values determine the maximum SDTR speed negotiated
14487 * with a device.
14488 *
14489 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14490 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14491 * without determining here whether the device supports SDTR.
14492 *
14493 * 4-bit speed SDTR speed name
14494 * =========== ===============
14495 * 0000b (0x0) SDTR disabled
14496 * 0001b (0x1) 5 Mhz
14497 * 0010b (0x2) 10 Mhz
14498 * 0011b (0x3) 20 Mhz (Ultra)
14499 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
14500 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
14501 * 0110b (0x6) Undefined
14502 * .
14503 * 1111b (0xF) Undefined
14504 */
14505 word = 0;
14506 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14507 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
14508 /* Set Ultra speed for TID 'tid'. */
14509 word |= (0x3 << (4 * (tid % 4)));
14510 } else {
14511 /* Set Fast speed for TID 'tid'. */
14512 word |= (0x2 << (4 * (tid % 4)));
14513 }
14514 if (tid == 3) { /* Check if done with sdtr_speed1. */
14515 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
14516 word = 0;
14517 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
14518 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
14519 word = 0;
14520 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
14521 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
14522 word = 0;
14523 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
14524 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
14525 /* End of loop. */
14526 }
14527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014528
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014529 /*
14530 * Set microcode operating variable for the disconnect per TID bitmask.
14531 */
14532 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14533 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014535 /*
14536 * Set SCSI_CFG0 Microcode Default Value.
14537 *
14538 * The microcode will set the SCSI_CFG0 register using this value
14539 * after it is started below.
14540 */
14541 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14542 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14543 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014544
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014545 /*
14546 * Determine SCSI_CFG1 Microcode Default Value.
14547 *
14548 * The microcode will set the SCSI_CFG1 register using this value
14549 * after it is started below.
14550 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014551
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014552 /* Read current SCSI_CFG1 Register value. */
14553 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014554
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014555 /*
14556 * If all three connectors are in use, return an error.
14557 */
14558 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
14559 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
14560 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
14561 return ADV_ERROR;
14562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014563
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014564 /*
14565 * If the internal narrow cable is reversed all of the SCSI_CTRL
14566 * register signals will be set. Check for and return an error if
14567 * this condition is found.
14568 */
14569 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14570 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14571 return ADV_ERROR;
14572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014573
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014574 /*
14575 * If this is a differential board and a single-ended device
14576 * is attached to one of the connectors, return an error.
14577 */
14578 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
14579 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
14580 return ADV_ERROR;
14581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014582
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014583 /*
14584 * If automatic termination control is enabled, then set the
14585 * termination value based on a table listed in a_condor.h.
14586 *
14587 * If manual termination was specified with an EEPROM setting
14588 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
14589 * is ready to be 'ored' into SCSI_CFG1.
14590 */
14591 if (asc_dvc->cfg->termination == 0) {
14592 /*
14593 * The software always controls termination by setting TERM_CTL_SEL.
14594 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
14595 */
14596 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014597
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014598 switch (scsi_cfg1 & CABLE_DETECT) {
14599 /* TERM_CTL_H: on, TERM_CTL_L: on */
14600 case 0x3:
14601 case 0x7:
14602 case 0xB:
14603 case 0xD:
14604 case 0xE:
14605 case 0xF:
14606 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
14607 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014608
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014609 /* TERM_CTL_H: on, TERM_CTL_L: off */
14610 case 0x1:
14611 case 0x5:
14612 case 0x9:
14613 case 0xA:
14614 case 0xC:
14615 asc_dvc->cfg->termination |= TERM_CTL_H;
14616 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014617
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014618 /* TERM_CTL_H: off, TERM_CTL_L: off */
14619 case 0x2:
14620 case 0x6:
14621 break;
14622 }
14623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014624
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014625 /*
14626 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
14627 */
14628 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014630 /*
14631 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
14632 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
14633 * referenced, because the hardware internally inverts
14634 * the Termination High and Low bits if TERM_POL is set.
14635 */
14636 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014637
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014638 /*
14639 * Set SCSI_CFG1 Microcode Default Value
14640 *
14641 * Set filter value and possibly modified termination control
14642 * bits in the Microcode SCSI_CFG1 Register Value.
14643 *
14644 * The microcode will set the SCSI_CFG1 register using this value
14645 * after it is started below.
14646 */
14647 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14648 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014649
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014650 /*
14651 * Set MEM_CFG Microcode Default Value
14652 *
14653 * The microcode will set the MEM_CFG register using this value
14654 * after it is started below.
14655 *
14656 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14657 * are defined.
14658 *
14659 * ASC-3550 has 8KB internal memory.
14660 */
14661 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14662 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014663
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014664 /*
14665 * Set SEL_MASK Microcode Default Value
14666 *
14667 * The microcode will set the SEL_MASK register using this value
14668 * after it is started below.
14669 */
14670 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14671 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014672
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014673 /*
14674 * Build carrier freelist.
14675 *
14676 * Driver must have already allocated memory and set 'carrier_buf'.
14677 */
14678 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014679
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014680 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14681 asc_dvc->carr_freelist = NULL;
14682 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14683 buf_size = ADV_CARRIER_BUFSIZE;
14684 } else {
14685 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014687
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014688 do {
14689 /*
14690 * Get physical address of the carrier 'carrp'.
14691 */
14692 contig_len = sizeof(ADV_CARR_T);
14693 carr_paddr =
14694 cpu_to_le32(DvcGetPhyAddr
14695 (asc_dvc, NULL, (uchar *)carrp,
14696 (ADV_SDCNT *)&contig_len,
14697 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014698
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014699 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014700
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014701 /*
14702 * If the current carrier is not physically contiguous, then
14703 * maybe there was a page crossing. Try the next carrier aligned
14704 * start address.
14705 */
14706 if (contig_len < sizeof(ADV_CARR_T)) {
14707 carrp++;
14708 continue;
14709 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014710
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014711 carrp->carr_pa = carr_paddr;
14712 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014713
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014714 /*
14715 * Insert the carrier at the beginning of the freelist.
14716 */
14717 carrp->next_vpa =
14718 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14719 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014720
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014721 carrp++;
14722 }
14723 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014724
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014725 /*
14726 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14727 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014728
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014729 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14730 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14731 return ADV_ERROR;
14732 }
14733 asc_dvc->carr_freelist = (ADV_CARR_T *)
14734 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014735
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014736 /*
14737 * The first command issued will be placed in the stopper carrier.
14738 */
14739 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014740
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014741 /*
14742 * Set RISC ICQ physical address start value.
14743 */
14744 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014746 /*
14747 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14748 */
14749 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14750 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14751 return ADV_ERROR;
14752 }
14753 asc_dvc->carr_freelist = (ADV_CARR_T *)
14754 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014755
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014756 /*
14757 * The first command completed by the RISC will be placed in
14758 * the stopper.
14759 *
14760 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14761 * completed the RISC will set the ASC_RQ_STOPPER bit.
14762 */
14763 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014764
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014765 /*
14766 * Set RISC IRQ physical address start value.
14767 */
14768 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14769 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014770
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014771 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14772 (ADV_INTR_ENABLE_HOST_INTR |
14773 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014774
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014775 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14776 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014777
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014778 /* finally, finally, gentlemen, start your engine */
14779 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014781 /*
14782 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14783 * Resets should be performed. The RISC has to be running
14784 * to issue a SCSI Bus Reset.
14785 */
14786 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14787 /*
14788 * If the BIOS Signature is present in memory, restore the
14789 * BIOS Handshake Configuration Table and do not perform
14790 * a SCSI Bus Reset.
14791 */
14792 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14793 0x55AA) {
14794 /*
14795 * Restore per TID negotiated values.
14796 */
14797 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14798 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14799 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14800 tagqng_able);
14801 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14802 AdvWriteByteLram(iop_base,
14803 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14804 max_cmd[tid]);
14805 }
14806 } else {
14807 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14808 warn_code = ASC_WARN_BUSRESET_ERROR;
14809 }
14810 }
14811 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014812
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014813 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014814}
14815
14816/*
14817 * Initialize the ASC-38C0800.
14818 *
14819 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14820 *
14821 * For a non-fatal error return a warning code. If there are no warnings
14822 * then 0 is returned.
14823 *
14824 * Needed after initialization for error recovery.
14825 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014826static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014827{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014828 AdvPortAddr iop_base;
14829 ushort warn_code;
14830 ADV_DCNT sum;
14831 int begin_addr;
14832 int end_addr;
14833 ushort code_sum;
14834 int word;
14835 int j;
14836 int adv_asc38C0800_expanded_size;
14837 ADV_CARR_T *carrp;
14838 ADV_DCNT contig_len;
14839 ADV_SDCNT buf_size;
14840 ADV_PADDR carr_paddr;
14841 int i;
14842 ushort scsi_cfg1;
14843 uchar byte;
14844 uchar tid;
14845 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14846 ushort wdtr_able, sdtr_able, tagqng_able;
14847 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014848
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014849 /* If there is already an error, don't continue. */
14850 if (asc_dvc->err_code != 0) {
14851 return ADV_ERROR;
14852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014853
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014854 /*
14855 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14856 */
14857 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14858 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14859 return ADV_ERROR;
14860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014861
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014862 warn_code = 0;
14863 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014864
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014865 /*
14866 * Save the RISC memory BIOS region before writing the microcode.
14867 * The BIOS may already be loaded and using its RISC LRAM region
14868 * so its region must be saved and restored.
14869 *
14870 * Note: This code makes the assumption, which is currently true,
14871 * that a chip reset does not clear RISC LRAM.
14872 */
14873 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14874 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14875 bios_mem[i]);
14876 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014877
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014878 /*
14879 * Save current per TID negotiated values.
14880 */
14881 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14882 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14883 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14884 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14885 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14886 max_cmd[tid]);
14887 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014888
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014889 /*
14890 * RAM BIST (RAM Built-In Self Test)
14891 *
14892 * Address : I/O base + offset 0x38h register (byte).
14893 * Function: Bit 7-6(RW) : RAM mode
14894 * Normal Mode : 0x00
14895 * Pre-test Mode : 0x40
14896 * RAM Test Mode : 0x80
14897 * Bit 5 : unused
14898 * Bit 4(RO) : Done bit
14899 * Bit 3-0(RO) : Status
14900 * Host Error : 0x08
14901 * Int_RAM Error : 0x04
14902 * RISC Error : 0x02
14903 * SCSI Error : 0x01
14904 * No Error : 0x00
14905 *
14906 * Note: RAM BIST code should be put right here, before loading the
14907 * microcode and after saving the RISC memory BIOS region.
14908 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014909
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014910 /*
14911 * LRAM Pre-test
14912 *
14913 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14914 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14915 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14916 * to NORMAL_MODE, return an error too.
14917 */
14918 for (i = 0; i < 2; i++) {
14919 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14920 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14921 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14922 if ((byte & RAM_TEST_DONE) == 0
14923 || (byte & 0x0F) != PRE_TEST_VALUE) {
14924 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14925 return ADV_ERROR;
14926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014927
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014928 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14929 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14930 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14931 != NORMAL_VALUE) {
14932 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14933 return ADV_ERROR;
14934 }
14935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014936
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014937 /*
14938 * LRAM Test - It takes about 1.5 ms to run through the test.
14939 *
14940 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14941 * If Done bit not set or Status not 0, save register byte, set the
14942 * err_code, and return an error.
14943 */
14944 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14945 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014946
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014947 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14948 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14949 /* Get here if Done bit not set or Status not 0. */
14950 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14951 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14952 return ADV_ERROR;
14953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014954
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014955 /* We need to reset back to normal mode after LRAM test passes. */
14956 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014957
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014958 /*
14959 * Load the Microcode
14960 *
14961 * Write the microcode image to RISC memory starting at address 0.
14962 *
14963 */
14964 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014965
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014966 /* Assume the following compressed format of the microcode buffer:
14967 *
14968 * 254 word (508 byte) table indexed by byte code followed
14969 * by the following byte codes:
14970 *
14971 * 1-Byte Code:
14972 * 00: Emit word 0 in table.
14973 * 01: Emit word 1 in table.
14974 * .
14975 * FD: Emit word 253 in table.
14976 *
14977 * Multi-Byte Code:
14978 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14979 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14980 */
14981 word = 0;
14982 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
14983 if (_adv_asc38C0800_buf[i] == 0xff) {
14984 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
14985 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14986 _adv_asc38C0800_buf
14987 [i +
14988 3] << 8) |
14989 _adv_asc38C0800_buf
14990 [i + 2]));
14991 word++;
14992 }
14993 i += 3;
14994 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
14995 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14996 _adv_asc38C0800_buf
14997 [i +
14998 2] << 8) |
14999 _adv_asc38C0800_buf[i
15000 +
15001 1]));
15002 i += 2;
15003 word++;
15004 } else {
15005 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15006 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
15007 word++;
15008 }
15009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015011 /*
15012 * Set 'word' for later use to clear the rest of memory and save
15013 * the expanded mcode size.
15014 */
15015 word *= 2;
15016 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015017
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015018 /*
15019 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
15020 */
15021 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
15022 AdvWriteWordAutoIncLram(iop_base, 0);
15023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015024
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015025 /*
15026 * Verify the microcode checksum.
15027 */
15028 sum = 0;
15029 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015031 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
15032 sum += AdvReadWordAutoIncLram(iop_base);
15033 }
15034 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015035
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015036 ASC_DBG2(1,
15037 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
15038 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015039
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015040 if (sum != _adv_asc38C0800_chksum) {
15041 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15042 return ADV_ERROR;
15043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015044
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015045 /*
15046 * Restore the RISC memory BIOS region.
15047 */
15048 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15049 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15050 bios_mem[i]);
15051 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015052
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015053 /*
15054 * Calculate and write the microcode code checksum to the microcode
15055 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15056 */
15057 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15058 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15059 code_sum = 0;
15060 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15061 for (word = begin_addr; word < end_addr; word += 2) {
15062 code_sum += AdvReadWordAutoIncLram(iop_base);
15063 }
15064 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015065
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015066 /*
15067 * Read microcode version and date.
15068 */
15069 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15070 asc_dvc->cfg->mcode_date);
15071 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15072 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015073
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015074 /*
15075 * Set the chip type to indicate the ASC38C0800.
15076 */
15077 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015078
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015079 /*
15080 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15081 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15082 * cable detection and then we are able to read C_DET[3:0].
15083 *
15084 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15085 * Microcode Default Value' section below.
15086 */
15087 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15088 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15089 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015090
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015091 /*
15092 * If the PCI Configuration Command Register "Parity Error Response
15093 * Control" Bit was clear (0), then set the microcode variable
15094 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15095 * to ignore DMA parity errors.
15096 */
15097 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15098 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15099 word |= CONTROL_FLAG_IGNORE_PERR;
15100 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015102
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015103 /*
15104 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
15105 * bits for the default FIFO threshold.
15106 *
15107 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
15108 *
15109 * For DMA Errata #4 set the BC_THRESH_ENB bit.
15110 */
15111 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15112 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
15113 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015114
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015115 /*
15116 * Microcode operating variables for WDTR, SDTR, and command tag
15117 * queuing will be set in AdvInquiryHandling() based on what a
15118 * device reports it is capable of in Inquiry byte 7.
15119 *
15120 * If SCSI Bus Resets have been disabled, then directly set
15121 * SDTR and WDTR from the EEPROM configuration. This will allow
15122 * the BIOS and warm boot to work without a SCSI bus hang on
15123 * the Inquiry caused by host and target mismatched DTR values.
15124 * Without the SCSI Bus Reset, before an Inquiry a device can't
15125 * be assumed to be in Asynchronous, Narrow mode.
15126 */
15127 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15128 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15129 asc_dvc->wdtr_able);
15130 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15131 asc_dvc->sdtr_able);
15132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015133
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015134 /*
15135 * Set microcode operating variables for DISC and SDTR_SPEED1,
15136 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15137 * configuration values.
15138 *
15139 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15140 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15141 * without determining here whether the device supports SDTR.
15142 */
15143 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15144 asc_dvc->cfg->disc_enable);
15145 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15146 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15147 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15148 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015149
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015150 /*
15151 * Set SCSI_CFG0 Microcode Default Value.
15152 *
15153 * The microcode will set the SCSI_CFG0 register using this value
15154 * after it is started below.
15155 */
15156 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15157 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15158 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015159
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015160 /*
15161 * Determine SCSI_CFG1 Microcode Default Value.
15162 *
15163 * The microcode will set the SCSI_CFG1 register using this value
15164 * after it is started below.
15165 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015166
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015167 /* Read current SCSI_CFG1 Register value. */
15168 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015169
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015170 /*
15171 * If the internal narrow cable is reversed all of the SCSI_CTRL
15172 * register signals will be set. Check for and return an error if
15173 * this condition is found.
15174 */
15175 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15176 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15177 return ADV_ERROR;
15178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015179
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015180 /*
15181 * All kind of combinations of devices attached to one of four connectors
15182 * are acceptable except HVD device attached. For example, LVD device can
15183 * be attached to SE connector while SE device attached to LVD connector.
15184 * If LVD device attached to SE connector, it only runs up to Ultra speed.
15185 *
15186 * If an HVD device is attached to one of LVD connectors, return an error.
15187 * However, there is no way to detect HVD device attached to SE connectors.
15188 */
15189 if (scsi_cfg1 & HVD) {
15190 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15191 return ADV_ERROR;
15192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015193
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015194 /*
15195 * If either SE or LVD automatic termination control is enabled, then
15196 * set the termination value based on a table listed in a_condor.h.
15197 *
15198 * If manual termination was specified with an EEPROM setting then
15199 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
15200 * be 'ored' into SCSI_CFG1.
15201 */
15202 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15203 /* SE automatic termination control is enabled. */
15204 switch (scsi_cfg1 & C_DET_SE) {
15205 /* TERM_SE_HI: on, TERM_SE_LO: on */
15206 case 0x1:
15207 case 0x2:
15208 case 0x3:
15209 asc_dvc->cfg->termination |= TERM_SE;
15210 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015212 /* TERM_SE_HI: on, TERM_SE_LO: off */
15213 case 0x0:
15214 asc_dvc->cfg->termination |= TERM_SE_HI;
15215 break;
15216 }
15217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015218
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015219 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
15220 /* LVD automatic termination control is enabled. */
15221 switch (scsi_cfg1 & C_DET_LVD) {
15222 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
15223 case 0x4:
15224 case 0x8:
15225 case 0xC:
15226 asc_dvc->cfg->termination |= TERM_LVD;
15227 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015228
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015229 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
15230 case 0x0:
15231 break;
15232 }
15233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015234
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015235 /*
15236 * Clear any set TERM_SE and TERM_LVD bits.
15237 */
15238 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015239
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015240 /*
15241 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
15242 */
15243 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015244
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015245 /*
15246 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
15247 * and set possibly modified termination control bits in the Microcode
15248 * SCSI_CFG1 Register Value.
15249 */
15250 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015251
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015252 /*
15253 * Set SCSI_CFG1 Microcode Default Value
15254 *
15255 * Set possibly modified termination control and reset DIS_TERM_DRV
15256 * bits in the Microcode SCSI_CFG1 Register Value.
15257 *
15258 * The microcode will set the SCSI_CFG1 register using this value
15259 * after it is started below.
15260 */
15261 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015263 /*
15264 * Set MEM_CFG Microcode Default Value
15265 *
15266 * The microcode will set the MEM_CFG register using this value
15267 * after it is started below.
15268 *
15269 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15270 * are defined.
15271 *
15272 * ASC-38C0800 has 16KB internal memory.
15273 */
15274 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15275 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015276
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015277 /*
15278 * Set SEL_MASK Microcode Default Value
15279 *
15280 * The microcode will set the SEL_MASK register using this value
15281 * after it is started below.
15282 */
15283 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15284 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015285
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015286 /*
15287 * Build the carrier freelist.
15288 *
15289 * Driver must have already allocated memory and set 'carrier_buf'.
15290 */
15291 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015292
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015293 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15294 asc_dvc->carr_freelist = NULL;
15295 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15296 buf_size = ADV_CARRIER_BUFSIZE;
15297 } else {
15298 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015300
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015301 do {
15302 /*
15303 * Get physical address for the carrier 'carrp'.
15304 */
15305 contig_len = sizeof(ADV_CARR_T);
15306 carr_paddr =
15307 cpu_to_le32(DvcGetPhyAddr
15308 (asc_dvc, NULL, (uchar *)carrp,
15309 (ADV_SDCNT *)&contig_len,
15310 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015311
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015312 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015313
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015314 /*
15315 * If the current carrier is not physically contiguous, then
15316 * maybe there was a page crossing. Try the next carrier aligned
15317 * start address.
15318 */
15319 if (contig_len < sizeof(ADV_CARR_T)) {
15320 carrp++;
15321 continue;
15322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015323
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015324 carrp->carr_pa = carr_paddr;
15325 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015326
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015327 /*
15328 * Insert the carrier at the beginning of the freelist.
15329 */
15330 carrp->next_vpa =
15331 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15332 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015333
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015334 carrp++;
15335 }
15336 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015337
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015338 /*
15339 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15340 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015341
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015342 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15343 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15344 return ADV_ERROR;
15345 }
15346 asc_dvc->carr_freelist = (ADV_CARR_T *)
15347 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015348
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015349 /*
15350 * The first command issued will be placed in the stopper carrier.
15351 */
15352 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015353
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015354 /*
15355 * Set RISC ICQ physical address start value.
15356 * carr_pa is LE, must be native before write
15357 */
15358 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015359
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015360 /*
15361 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15362 */
15363 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15364 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15365 return ADV_ERROR;
15366 }
15367 asc_dvc->carr_freelist = (ADV_CARR_T *)
15368 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015369
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015370 /*
15371 * The first command completed by the RISC will be placed in
15372 * the stopper.
15373 *
15374 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15375 * completed the RISC will set the ASC_RQ_STOPPER bit.
15376 */
15377 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015378
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015379 /*
15380 * Set RISC IRQ physical address start value.
15381 *
15382 * carr_pa is LE, must be native before write *
15383 */
15384 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15385 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015386
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015387 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15388 (ADV_INTR_ENABLE_HOST_INTR |
15389 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015390
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015391 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15392 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015393
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015394 /* finally, finally, gentlemen, start your engine */
15395 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015396
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015397 /*
15398 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15399 * Resets should be performed. The RISC has to be running
15400 * to issue a SCSI Bus Reset.
15401 */
15402 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15403 /*
15404 * If the BIOS Signature is present in memory, restore the
15405 * BIOS Handshake Configuration Table and do not perform
15406 * a SCSI Bus Reset.
15407 */
15408 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15409 0x55AA) {
15410 /*
15411 * Restore per TID negotiated values.
15412 */
15413 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15414 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15415 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15416 tagqng_able);
15417 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15418 AdvWriteByteLram(iop_base,
15419 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15420 max_cmd[tid]);
15421 }
15422 } else {
15423 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15424 warn_code = ASC_WARN_BUSRESET_ERROR;
15425 }
15426 }
15427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015428
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015429 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015430}
15431
15432/*
15433 * Initialize the ASC-38C1600.
15434 *
15435 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15436 *
15437 * For a non-fatal error return a warning code. If there are no warnings
15438 * then 0 is returned.
15439 *
15440 * Needed after initialization for error recovery.
15441 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015442static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015443{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015444 AdvPortAddr iop_base;
15445 ushort warn_code;
15446 ADV_DCNT sum;
15447 int begin_addr;
15448 int end_addr;
15449 ushort code_sum;
15450 long word;
15451 int j;
15452 int adv_asc38C1600_expanded_size;
15453 ADV_CARR_T *carrp;
15454 ADV_DCNT contig_len;
15455 ADV_SDCNT buf_size;
15456 ADV_PADDR carr_paddr;
15457 int i;
15458 ushort scsi_cfg1;
15459 uchar byte;
15460 uchar tid;
15461 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
15462 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
15463 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070015464
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015465 /* If there is already an error, don't continue. */
15466 if (asc_dvc->err_code != 0) {
15467 return ADV_ERROR;
15468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015469
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015470 /*
15471 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
15472 */
15473 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
15474 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
15475 return ADV_ERROR;
15476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015477
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015478 warn_code = 0;
15479 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015481 /*
15482 * Save the RISC memory BIOS region before writing the microcode.
15483 * The BIOS may already be loaded and using its RISC LRAM region
15484 * so its region must be saved and restored.
15485 *
15486 * Note: This code makes the assumption, which is currently true,
15487 * that a chip reset does not clear RISC LRAM.
15488 */
15489 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15490 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15491 bios_mem[i]);
15492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015494 /*
15495 * Save current per TID negotiated values.
15496 */
15497 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15498 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15499 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15500 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
15501 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15502 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
15503 max_cmd[tid]);
15504 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015505
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015506 /*
15507 * RAM BIST (Built-In Self Test)
15508 *
15509 * Address : I/O base + offset 0x38h register (byte).
15510 * Function: Bit 7-6(RW) : RAM mode
15511 * Normal Mode : 0x00
15512 * Pre-test Mode : 0x40
15513 * RAM Test Mode : 0x80
15514 * Bit 5 : unused
15515 * Bit 4(RO) : Done bit
15516 * Bit 3-0(RO) : Status
15517 * Host Error : 0x08
15518 * Int_RAM Error : 0x04
15519 * RISC Error : 0x02
15520 * SCSI Error : 0x01
15521 * No Error : 0x00
15522 *
15523 * Note: RAM BIST code should be put right here, before loading the
15524 * microcode and after saving the RISC memory BIOS region.
15525 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015526
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015527 /*
15528 * LRAM Pre-test
15529 *
15530 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
15531 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
15532 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
15533 * to NORMAL_MODE, return an error too.
15534 */
15535 for (i = 0; i < 2; i++) {
15536 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
15537 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15538 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15539 if ((byte & RAM_TEST_DONE) == 0
15540 || (byte & 0x0F) != PRE_TEST_VALUE) {
15541 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15542 return ADV_ERROR;
15543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015544
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015545 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
15546 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15547 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
15548 != NORMAL_VALUE) {
15549 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15550 return ADV_ERROR;
15551 }
15552 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015553
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015554 /*
15555 * LRAM Test - It takes about 1.5 ms to run through the test.
15556 *
15557 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
15558 * If Done bit not set or Status not 0, save register byte, set the
15559 * err_code, and return an error.
15560 */
15561 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
15562 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015563
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015564 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15565 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
15566 /* Get here if Done bit not set or Status not 0. */
15567 asc_dvc->bist_err_code = byte; /* for BIOS display message */
15568 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
15569 return ADV_ERROR;
15570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015571
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015572 /* We need to reset back to normal mode after LRAM test passes. */
15573 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015575 /*
15576 * Load the Microcode
15577 *
15578 * Write the microcode image to RISC memory starting at address 0.
15579 *
15580 */
15581 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015582
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015583 /*
15584 * Assume the following compressed format of the microcode buffer:
15585 *
15586 * 254 word (508 byte) table indexed by byte code followed
15587 * by the following byte codes:
15588 *
15589 * 1-Byte Code:
15590 * 00: Emit word 0 in table.
15591 * 01: Emit word 1 in table.
15592 * .
15593 * FD: Emit word 253 in table.
15594 *
15595 * Multi-Byte Code:
15596 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15597 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15598 */
15599 word = 0;
15600 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
15601 if (_adv_asc38C1600_buf[i] == 0xff) {
15602 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
15603 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15604 _adv_asc38C1600_buf
15605 [i +
15606 3] << 8) |
15607 _adv_asc38C1600_buf
15608 [i + 2]));
15609 word++;
15610 }
15611 i += 3;
15612 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
15613 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15614 _adv_asc38C1600_buf
15615 [i +
15616 2] << 8) |
15617 _adv_asc38C1600_buf[i
15618 +
15619 1]));
15620 i += 2;
15621 word++;
15622 } else {
15623 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15624 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
15625 word++;
15626 }
15627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015629 /*
15630 * Set 'word' for later use to clear the rest of memory and save
15631 * the expanded mcode size.
15632 */
15633 word *= 2;
15634 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015635
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015636 /*
15637 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15638 */
15639 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15640 AdvWriteWordAutoIncLram(iop_base, 0);
15641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015643 /*
15644 * Verify the microcode checksum.
15645 */
15646 sum = 0;
15647 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015649 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15650 sum += AdvReadWordAutoIncLram(iop_base);
15651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015653 if (sum != _adv_asc38C1600_chksum) {
15654 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15655 return ADV_ERROR;
15656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015657
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015658 /*
15659 * Restore the RISC memory BIOS region.
15660 */
15661 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15662 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15663 bios_mem[i]);
15664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015665
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015666 /*
15667 * Calculate and write the microcode code checksum to the microcode
15668 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15669 */
15670 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15671 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15672 code_sum = 0;
15673 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15674 for (word = begin_addr; word < end_addr; word += 2) {
15675 code_sum += AdvReadWordAutoIncLram(iop_base);
15676 }
15677 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015678
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015679 /*
15680 * Read microcode version and date.
15681 */
15682 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15683 asc_dvc->cfg->mcode_date);
15684 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15685 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015686
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015687 /*
15688 * Set the chip type to indicate the ASC38C1600.
15689 */
15690 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015692 /*
15693 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15694 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15695 * cable detection and then we are able to read C_DET[3:0].
15696 *
15697 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15698 * Microcode Default Value' section below.
15699 */
15700 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15701 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15702 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015703
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015704 /*
15705 * If the PCI Configuration Command Register "Parity Error Response
15706 * Control" Bit was clear (0), then set the microcode variable
15707 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15708 * to ignore DMA parity errors.
15709 */
15710 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15711 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15712 word |= CONTROL_FLAG_IGNORE_PERR;
15713 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015715
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015716 /*
15717 * If the BIOS control flag AIPP (Asynchronous Information
15718 * Phase Protection) disable bit is not set, then set the firmware
15719 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15720 * AIPP checking and encoding.
15721 */
15722 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15723 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15724 word |= CONTROL_FLAG_ENABLE_AIPP;
15725 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015727
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015728 /*
15729 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15730 * and START_CTL_TH [3:2].
15731 */
15732 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15733 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015734
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015735 /*
15736 * Microcode operating variables for WDTR, SDTR, and command tag
15737 * queuing will be set in AdvInquiryHandling() based on what a
15738 * device reports it is capable of in Inquiry byte 7.
15739 *
15740 * If SCSI Bus Resets have been disabled, then directly set
15741 * SDTR and WDTR from the EEPROM configuration. This will allow
15742 * the BIOS and warm boot to work without a SCSI bus hang on
15743 * the Inquiry caused by host and target mismatched DTR values.
15744 * Without the SCSI Bus Reset, before an Inquiry a device can't
15745 * be assumed to be in Asynchronous, Narrow mode.
15746 */
15747 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15748 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15749 asc_dvc->wdtr_able);
15750 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15751 asc_dvc->sdtr_able);
15752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015753
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015754 /*
15755 * Set microcode operating variables for DISC and SDTR_SPEED1,
15756 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15757 * configuration values.
15758 *
15759 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15760 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15761 * without determining here whether the device supports SDTR.
15762 */
15763 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15764 asc_dvc->cfg->disc_enable);
15765 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15766 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15767 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15768 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015770 /*
15771 * Set SCSI_CFG0 Microcode Default Value.
15772 *
15773 * The microcode will set the SCSI_CFG0 register using this value
15774 * after it is started below.
15775 */
15776 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15777 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15778 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015779
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015780 /*
15781 * Calculate SCSI_CFG1 Microcode Default Value.
15782 *
15783 * The microcode will set the SCSI_CFG1 register using this value
15784 * after it is started below.
15785 *
15786 * Each ASC-38C1600 function has only two cable detect bits.
15787 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15788 */
15789 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015790
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015791 /*
15792 * If the cable is reversed all of the SCSI_CTRL register signals
15793 * will be set. Check for and return an error if this condition is
15794 * found.
15795 */
15796 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15797 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15798 return ADV_ERROR;
15799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015800
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015801 /*
15802 * Each ASC-38C1600 function has two connectors. Only an HVD device
15803 * can not be connected to either connector. An LVD device or SE device
15804 * may be connected to either connecor. If an SE device is connected,
15805 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15806 *
15807 * If an HVD device is attached, return an error.
15808 */
15809 if (scsi_cfg1 & HVD) {
15810 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15811 return ADV_ERROR;
15812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015813
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015814 /*
15815 * Each function in the ASC-38C1600 uses only the SE cable detect and
15816 * termination because there are two connectors for each function. Each
15817 * function may use either LVD or SE mode. Corresponding the SE automatic
15818 * termination control EEPROM bits are used for each function. Each
15819 * function has its own EEPROM. If SE automatic control is enabled for
15820 * the function, then set the termination value based on a table listed
15821 * in a_condor.h.
15822 *
15823 * If manual termination is specified in the EEPROM for the function,
15824 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15825 * ready to be 'ored' into SCSI_CFG1.
15826 */
15827 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15828 /* SE automatic termination control is enabled. */
15829 switch (scsi_cfg1 & C_DET_SE) {
15830 /* TERM_SE_HI: on, TERM_SE_LO: on */
15831 case 0x1:
15832 case 0x2:
15833 case 0x3:
15834 asc_dvc->cfg->termination |= TERM_SE;
15835 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015837 case 0x0:
15838 if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
15839 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15840 } else {
15841 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15842 asc_dvc->cfg->termination |= TERM_SE_HI;
15843 }
15844 break;
15845 }
15846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015847
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015848 /*
15849 * Clear any set TERM_SE bits.
15850 */
15851 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015852
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015853 /*
15854 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15855 */
15856 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015857
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015858 /*
15859 * Clear Big Endian and Terminator Polarity bits and set possibly
15860 * modified termination control bits in the Microcode SCSI_CFG1
15861 * Register Value.
15862 *
15863 * Big Endian bit is not used even on big endian machines.
15864 */
15865 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015866
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015867 /*
15868 * Set SCSI_CFG1 Microcode Default Value
15869 *
15870 * Set possibly modified termination control bits in the Microcode
15871 * SCSI_CFG1 Register Value.
15872 *
15873 * The microcode will set the SCSI_CFG1 register using this value
15874 * after it is started below.
15875 */
15876 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015877
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015878 /*
15879 * Set MEM_CFG Microcode Default Value
15880 *
15881 * The microcode will set the MEM_CFG register using this value
15882 * after it is started below.
15883 *
15884 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15885 * are defined.
15886 *
15887 * ASC-38C1600 has 32KB internal memory.
15888 *
15889 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15890 * out a special 16K Adv Library and Microcode version. After the issue
15891 * resolved, we should turn back to the 32K support. Both a_condor.h and
15892 * mcode.sas files also need to be updated.
15893 *
15894 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15895 * BIOS_EN | RAM_SZ_32KB);
15896 */
15897 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15898 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015899
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015900 /*
15901 * Set SEL_MASK Microcode Default Value
15902 *
15903 * The microcode will set the SEL_MASK register using this value
15904 * after it is started below.
15905 */
15906 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15907 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015908
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015909 /*
15910 * Build the carrier freelist.
15911 *
15912 * Driver must have already allocated memory and set 'carrier_buf'.
15913 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015914
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015915 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015916
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015917 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15918 asc_dvc->carr_freelist = NULL;
15919 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15920 buf_size = ADV_CARRIER_BUFSIZE;
15921 } else {
15922 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015924
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015925 do {
15926 /*
15927 * Get physical address for the carrier 'carrp'.
15928 */
15929 contig_len = sizeof(ADV_CARR_T);
15930 carr_paddr =
15931 cpu_to_le32(DvcGetPhyAddr
15932 (asc_dvc, NULL, (uchar *)carrp,
15933 (ADV_SDCNT *)&contig_len,
15934 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015935
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015936 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015937
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015938 /*
15939 * If the current carrier is not physically contiguous, then
15940 * maybe there was a page crossing. Try the next carrier aligned
15941 * start address.
15942 */
15943 if (contig_len < sizeof(ADV_CARR_T)) {
15944 carrp++;
15945 continue;
15946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015947
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015948 carrp->carr_pa = carr_paddr;
15949 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015950
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015951 /*
15952 * Insert the carrier at the beginning of the freelist.
15953 */
15954 carrp->next_vpa =
15955 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15956 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015957
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015958 carrp++;
15959 }
15960 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015961
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015962 /*
15963 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15964 */
15965 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15966 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15967 return ADV_ERROR;
15968 }
15969 asc_dvc->carr_freelist = (ADV_CARR_T *)
15970 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015971
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015972 /*
15973 * The first command issued will be placed in the stopper carrier.
15974 */
15975 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015976
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015977 /*
15978 * Set RISC ICQ physical address start value. Initialize the
15979 * COMMA register to the same value otherwise the RISC will
15980 * prematurely detect a command is available.
15981 */
15982 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
15983 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
15984 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015985
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015986 /*
15987 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15988 */
15989 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15990 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15991 return ADV_ERROR;
15992 }
15993 asc_dvc->carr_freelist = (ADV_CARR_T *)
15994 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015995
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015996 /*
15997 * The first command completed by the RISC will be placed in
15998 * the stopper.
15999 *
16000 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
16001 * completed the RISC will set the ASC_RQ_STOPPER bit.
16002 */
16003 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016004
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016005 /*
16006 * Set RISC IRQ physical address start value.
16007 */
16008 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
16009 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016011 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
16012 (ADV_INTR_ENABLE_HOST_INTR |
16013 ADV_INTR_ENABLE_GLOBAL_INTR));
16014 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
16015 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016016
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016017 /* finally, finally, gentlemen, start your engine */
16018 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016019
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016020 /*
16021 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
16022 * Resets should be performed. The RISC has to be running
16023 * to issue a SCSI Bus Reset.
16024 */
16025 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
16026 /*
16027 * If the BIOS Signature is present in memory, restore the
16028 * per TID microcode operating variables.
16029 */
16030 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
16031 0x55AA) {
16032 /*
16033 * Restore per TID negotiated values.
16034 */
16035 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16036 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16037 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16038 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
16039 tagqng_able);
16040 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
16041 AdvWriteByteLram(iop_base,
16042 ASC_MC_NUMBER_OF_MAX_CMD + tid,
16043 max_cmd[tid]);
16044 }
16045 } else {
16046 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
16047 warn_code = ASC_WARN_BUSRESET_ERROR;
16048 }
16049 }
16050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016051
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016052 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016053}
16054
16055/*
16056 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
16057 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
16058 * all of this is done.
16059 *
16060 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
16061 *
16062 * For a non-fatal error return a warning code. If there are no warnings
16063 * then 0 is returned.
16064 *
16065 * Note: Chip is stopped on entry.
16066 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016067static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016068{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016069 AdvPortAddr iop_base;
16070 ushort warn_code;
16071 ADVEEP_3550_CONFIG eep_config;
16072 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016073
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016074 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016075
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016076 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016077
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016078 /*
16079 * Read the board's EEPROM configuration.
16080 *
16081 * Set default values if a bad checksum is found.
16082 */
16083 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
16084 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016085
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016086 /*
16087 * Set EEPROM default values.
16088 */
16089 for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
16090 *((uchar *)&eep_config + i) =
16091 *((uchar *)&Default_3550_EEPROM_Config + i);
16092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016094 /*
16095 * Assume the 6 byte board serial number that was read
16096 * from EEPROM is correct even if the EEPROM checksum
16097 * failed.
16098 */
16099 eep_config.serial_number_word3 =
16100 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016101
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016102 eep_config.serial_number_word2 =
16103 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016104
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016105 eep_config.serial_number_word1 =
16106 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016107
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016108 AdvSet3550EEPConfig(iop_base, &eep_config);
16109 }
16110 /*
16111 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
16112 * EEPROM configuration that was read.
16113 *
16114 * This is the mapping of EEPROM fields to Adv Library fields.
16115 */
16116 asc_dvc->wdtr_able = eep_config.wdtr_able;
16117 asc_dvc->sdtr_able = eep_config.sdtr_able;
16118 asc_dvc->ultra_able = eep_config.ultra_able;
16119 asc_dvc->tagqng_able = eep_config.tagqng_able;
16120 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16121 asc_dvc->max_host_qng = eep_config.max_host_qng;
16122 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16123 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
16124 asc_dvc->start_motor = eep_config.start_motor;
16125 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16126 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16127 asc_dvc->no_scam = eep_config.scam_tolerant;
16128 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
16129 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
16130 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016131
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016132 /*
16133 * Set the host maximum queuing (max. 253, min. 16) and the per device
16134 * maximum queuing (max. 63, min. 4).
16135 */
16136 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16137 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16138 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16139 /* If the value is zero, assume it is uninitialized. */
16140 if (eep_config.max_host_qng == 0) {
16141 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16142 } else {
16143 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16144 }
16145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016146
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016147 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16148 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16149 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16150 /* If the value is zero, assume it is uninitialized. */
16151 if (eep_config.max_dvc_qng == 0) {
16152 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16153 } else {
16154 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16155 }
16156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016157
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016158 /*
16159 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16160 * set 'max_dvc_qng' to 'max_host_qng'.
16161 */
16162 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16163 eep_config.max_dvc_qng = eep_config.max_host_qng;
16164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016165
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016166 /*
16167 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
16168 * values based on possibly adjusted EEPROM values.
16169 */
16170 asc_dvc->max_host_qng = eep_config.max_host_qng;
16171 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016172
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016173 /*
16174 * If the EEPROM 'termination' field is set to automatic (0), then set
16175 * the ADV_DVC_CFG 'termination' field to automatic also.
16176 *
16177 * If the termination is specified with a non-zero 'termination'
16178 * value check that a legal value is set and set the ADV_DVC_CFG
16179 * 'termination' field appropriately.
16180 */
16181 if (eep_config.termination == 0) {
16182 asc_dvc->cfg->termination = 0; /* auto termination */
16183 } else {
16184 /* Enable manual control with low off / high off. */
16185 if (eep_config.termination == 1) {
16186 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016187
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016188 /* Enable manual control with low off / high on. */
16189 } else if (eep_config.termination == 2) {
16190 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016191
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016192 /* Enable manual control with low on / high on. */
16193 } else if (eep_config.termination == 3) {
16194 asc_dvc->cfg->termination =
16195 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
16196 } else {
16197 /*
16198 * The EEPROM 'termination' field contains a bad value. Use
16199 * automatic termination instead.
16200 */
16201 asc_dvc->cfg->termination = 0;
16202 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16203 }
16204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016205
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016206 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016207}
16208
16209/*
16210 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
16211 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
16212 * all of this is done.
16213 *
16214 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
16215 *
16216 * For a non-fatal error return a warning code. If there are no warnings
16217 * then 0 is returned.
16218 *
16219 * Note: Chip is stopped on entry.
16220 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016221static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016222{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016223 AdvPortAddr iop_base;
16224 ushort warn_code;
16225 ADVEEP_38C0800_CONFIG eep_config;
16226 int i;
16227 uchar tid, termination;
16228 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016229
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016230 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016231
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016232 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016233
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016234 /*
16235 * Read the board's EEPROM configuration.
16236 *
16237 * Set default values if a bad checksum is found.
16238 */
16239 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
16240 eep_config.check_sum) {
16241 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016242
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016243 /*
16244 * Set EEPROM default values.
16245 */
16246 for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
16247 *((uchar *)&eep_config + i) =
16248 *((uchar *)&Default_38C0800_EEPROM_Config + i);
16249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016250
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016251 /*
16252 * Assume the 6 byte board serial number that was read
16253 * from EEPROM is correct even if the EEPROM checksum
16254 * failed.
16255 */
16256 eep_config.serial_number_word3 =
16257 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016258
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016259 eep_config.serial_number_word2 =
16260 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016261
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016262 eep_config.serial_number_word1 =
16263 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016264
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016265 AdvSet38C0800EEPConfig(iop_base, &eep_config);
16266 }
16267 /*
16268 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
16269 * EEPROM configuration that was read.
16270 *
16271 * This is the mapping of EEPROM fields to Adv Library fields.
16272 */
16273 asc_dvc->wdtr_able = eep_config.wdtr_able;
16274 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
16275 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
16276 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
16277 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
16278 asc_dvc->tagqng_able = eep_config.tagqng_able;
16279 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16280 asc_dvc->max_host_qng = eep_config.max_host_qng;
16281 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16282 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
16283 asc_dvc->start_motor = eep_config.start_motor;
16284 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16285 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16286 asc_dvc->no_scam = eep_config.scam_tolerant;
16287 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
16288 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
16289 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016290
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016291 /*
16292 * For every Target ID if any of its 'sdtr_speed[1234]' bits
16293 * are set, then set an 'sdtr_able' bit for it.
16294 */
16295 asc_dvc->sdtr_able = 0;
16296 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16297 if (tid == 0) {
16298 sdtr_speed = asc_dvc->sdtr_speed1;
16299 } else if (tid == 4) {
16300 sdtr_speed = asc_dvc->sdtr_speed2;
16301 } else if (tid == 8) {
16302 sdtr_speed = asc_dvc->sdtr_speed3;
16303 } else if (tid == 12) {
16304 sdtr_speed = asc_dvc->sdtr_speed4;
16305 }
16306 if (sdtr_speed & ADV_MAX_TID) {
16307 asc_dvc->sdtr_able |= (1 << tid);
16308 }
16309 sdtr_speed >>= 4;
16310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016311
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016312 /*
16313 * Set the host maximum queuing (max. 253, min. 16) and the per device
16314 * maximum queuing (max. 63, min. 4).
16315 */
16316 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16317 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16318 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16319 /* If the value is zero, assume it is uninitialized. */
16320 if (eep_config.max_host_qng == 0) {
16321 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16322 } else {
16323 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16324 }
16325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016326
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016327 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16328 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16329 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16330 /* If the value is zero, assume it is uninitialized. */
16331 if (eep_config.max_dvc_qng == 0) {
16332 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16333 } else {
16334 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16335 }
16336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016337
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016338 /*
16339 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16340 * set 'max_dvc_qng' to 'max_host_qng'.
16341 */
16342 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16343 eep_config.max_dvc_qng = eep_config.max_host_qng;
16344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016345
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016346 /*
16347 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
16348 * values based on possibly adjusted EEPROM values.
16349 */
16350 asc_dvc->max_host_qng = eep_config.max_host_qng;
16351 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016352
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016353 /*
16354 * If the EEPROM 'termination' field is set to automatic (0), then set
16355 * the ADV_DVC_CFG 'termination' field to automatic also.
16356 *
16357 * If the termination is specified with a non-zero 'termination'
16358 * value check that a legal value is set and set the ADV_DVC_CFG
16359 * 'termination' field appropriately.
16360 */
16361 if (eep_config.termination_se == 0) {
16362 termination = 0; /* auto termination for SE */
16363 } else {
16364 /* Enable manual control with low off / high off. */
16365 if (eep_config.termination_se == 1) {
16366 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016367
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016368 /* Enable manual control with low off / high on. */
16369 } else if (eep_config.termination_se == 2) {
16370 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016371
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016372 /* Enable manual control with low on / high on. */
16373 } else if (eep_config.termination_se == 3) {
16374 termination = TERM_SE;
16375 } else {
16376 /*
16377 * The EEPROM 'termination_se' field contains a bad value.
16378 * Use automatic termination instead.
16379 */
16380 termination = 0;
16381 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16382 }
16383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016384
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016385 if (eep_config.termination_lvd == 0) {
16386 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16387 } else {
16388 /* Enable manual control with low off / high off. */
16389 if (eep_config.termination_lvd == 1) {
16390 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016391
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016392 /* Enable manual control with low off / high on. */
16393 } else if (eep_config.termination_lvd == 2) {
16394 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016395
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016396 /* Enable manual control with low on / high on. */
16397 } else if (eep_config.termination_lvd == 3) {
16398 asc_dvc->cfg->termination = termination | TERM_LVD;
16399 } else {
16400 /*
16401 * The EEPROM 'termination_lvd' field contains a bad value.
16402 * Use automatic termination instead.
16403 */
16404 asc_dvc->cfg->termination = termination;
16405 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16406 }
16407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016408
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016409 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016410}
16411
16412/*
16413 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
16414 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
16415 * all of this is done.
16416 *
16417 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
16418 *
16419 * For a non-fatal error return a warning code. If there are no warnings
16420 * then 0 is returned.
16421 *
16422 * Note: Chip is stopped on entry.
16423 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016424static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016425{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016426 AdvPortAddr iop_base;
16427 ushort warn_code;
16428 ADVEEP_38C1600_CONFIG eep_config;
16429 int i;
16430 uchar tid, termination;
16431 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016432
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016433 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016434
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016435 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016436
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016437 /*
16438 * Read the board's EEPROM configuration.
16439 *
16440 * Set default values if a bad checksum is found.
16441 */
16442 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
16443 eep_config.check_sum) {
16444 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016445
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016446 /*
16447 * Set EEPROM default values.
16448 */
16449 for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
16450 if (i == 1
16451 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
16452 0) {
16453 /*
16454 * Set Function 1 EEPROM Word 0 MSB
16455 *
16456 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
16457 * EEPROM bits.
16458 *
16459 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
16460 * old Mac system booting problem. The Expansion ROM must
16461 * be disabled in Function 1 for these systems.
16462 *
16463 */
16464 *((uchar *)&eep_config + i) =
16465 ((*
16466 ((uchar *)&Default_38C1600_EEPROM_Config
16467 +
16468 i)) &
16469 (~
16470 (((ADV_EEPROM_BIOS_ENABLE |
16471 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016473 /*
16474 * Set the INTAB (bit 11) if the GPIO 0 input indicates
16475 * the Function 1 interrupt line is wired to INTA.
16476 *
16477 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
16478 * 1 - Function 1 interrupt line wired to INT A.
16479 * 0 - Function 1 interrupt line wired to INT B.
16480 *
16481 * Note: Adapter boards always have Function 0 wired to INTA.
16482 * Put all 5 GPIO bits in input mode and then read
16483 * their input values.
16484 */
16485 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
16486 0);
16487 if (AdvReadByteRegister
16488 (iop_base, IOPB_GPIO_DATA) & 0x01) {
16489 /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
16490 *((uchar *)&eep_config + i) |=
16491 ((ADV_EEPROM_INTAB >> 8) & 0xFF);
16492 }
16493 } else {
16494 *((uchar *)&eep_config + i) =
16495 *((uchar *)&Default_38C1600_EEPROM_Config
16496 + i);
16497 }
16498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016499
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016500 /*
16501 * Assume the 6 byte board serial number that was read
16502 * from EEPROM is correct even if the EEPROM checksum
16503 * failed.
16504 */
16505 eep_config.serial_number_word3 =
16506 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016507
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016508 eep_config.serial_number_word2 =
16509 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016510
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016511 eep_config.serial_number_word1 =
16512 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016513
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016514 AdvSet38C1600EEPConfig(iop_base, &eep_config);
16515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016516
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016517 /*
16518 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
16519 * EEPROM configuration that was read.
16520 *
16521 * This is the mapping of EEPROM fields to Adv Library fields.
16522 */
16523 asc_dvc->wdtr_able = eep_config.wdtr_able;
16524 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
16525 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
16526 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
16527 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
16528 asc_dvc->ppr_able = 0;
16529 asc_dvc->tagqng_able = eep_config.tagqng_able;
16530 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16531 asc_dvc->max_host_qng = eep_config.max_host_qng;
16532 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16533 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
16534 asc_dvc->start_motor = eep_config.start_motor;
16535 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16536 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16537 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016538
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016539 /*
16540 * For every Target ID if any of its 'sdtr_speed[1234]' bits
16541 * are set, then set an 'sdtr_able' bit for it.
16542 */
16543 asc_dvc->sdtr_able = 0;
16544 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
16545 if (tid == 0) {
16546 sdtr_speed = asc_dvc->sdtr_speed1;
16547 } else if (tid == 4) {
16548 sdtr_speed = asc_dvc->sdtr_speed2;
16549 } else if (tid == 8) {
16550 sdtr_speed = asc_dvc->sdtr_speed3;
16551 } else if (tid == 12) {
16552 sdtr_speed = asc_dvc->sdtr_speed4;
16553 }
16554 if (sdtr_speed & ASC_MAX_TID) {
16555 asc_dvc->sdtr_able |= (1 << tid);
16556 }
16557 sdtr_speed >>= 4;
16558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016559
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016560 /*
16561 * Set the host maximum queuing (max. 253, min. 16) and the per device
16562 * maximum queuing (max. 63, min. 4).
16563 */
16564 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16565 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16566 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16567 /* If the value is zero, assume it is uninitialized. */
16568 if (eep_config.max_host_qng == 0) {
16569 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16570 } else {
16571 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16572 }
16573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016575 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16576 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16577 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16578 /* If the value is zero, assume it is uninitialized. */
16579 if (eep_config.max_dvc_qng == 0) {
16580 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16581 } else {
16582 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16583 }
16584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016585
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016586 /*
16587 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16588 * set 'max_dvc_qng' to 'max_host_qng'.
16589 */
16590 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16591 eep_config.max_dvc_qng = eep_config.max_host_qng;
16592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016593
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016594 /*
16595 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
16596 * values based on possibly adjusted EEPROM values.
16597 */
16598 asc_dvc->max_host_qng = eep_config.max_host_qng;
16599 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016600
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016601 /*
16602 * If the EEPROM 'termination' field is set to automatic (0), then set
16603 * the ASC_DVC_CFG 'termination' field to automatic also.
16604 *
16605 * If the termination is specified with a non-zero 'termination'
16606 * value check that a legal value is set and set the ASC_DVC_CFG
16607 * 'termination' field appropriately.
16608 */
16609 if (eep_config.termination_se == 0) {
16610 termination = 0; /* auto termination for SE */
16611 } else {
16612 /* Enable manual control with low off / high off. */
16613 if (eep_config.termination_se == 1) {
16614 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016615
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016616 /* Enable manual control with low off / high on. */
16617 } else if (eep_config.termination_se == 2) {
16618 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016619
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016620 /* Enable manual control with low on / high on. */
16621 } else if (eep_config.termination_se == 3) {
16622 termination = TERM_SE;
16623 } else {
16624 /*
16625 * The EEPROM 'termination_se' field contains a bad value.
16626 * Use automatic termination instead.
16627 */
16628 termination = 0;
16629 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16630 }
16631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016632
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016633 if (eep_config.termination_lvd == 0) {
16634 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16635 } else {
16636 /* Enable manual control with low off / high off. */
16637 if (eep_config.termination_lvd == 1) {
16638 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016639
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016640 /* Enable manual control with low off / high on. */
16641 } else if (eep_config.termination_lvd == 2) {
16642 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016643
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016644 /* Enable manual control with low on / high on. */
16645 } else if (eep_config.termination_lvd == 3) {
16646 asc_dvc->cfg->termination = termination | TERM_LVD;
16647 } else {
16648 /*
16649 * The EEPROM 'termination_lvd' field contains a bad value.
16650 * Use automatic termination instead.
16651 */
16652 asc_dvc->cfg->termination = termination;
16653 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16654 }
16655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016657 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016658}
16659
16660/*
16661 * Read EEPROM configuration into the specified buffer.
16662 *
16663 * Return a checksum based on the EEPROM configuration read.
16664 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016665static ushort __init
Linus Torvalds1da177e2005-04-16 15:20:36 -070016666AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16667{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016668 ushort wval, chksum;
16669 ushort *wbuf;
16670 int eep_addr;
16671 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016672
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016673 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16674 wbuf = (ushort *)cfg_buf;
16675 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016676
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016677 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16678 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16679 wval = AdvReadEEPWord(iop_base, eep_addr);
16680 chksum += wval; /* Checksum is calculated from word values. */
16681 if (*charfields++) {
16682 *wbuf = le16_to_cpu(wval);
16683 } else {
16684 *wbuf = wval;
16685 }
16686 }
16687 /* Read checksum word. */
16688 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16689 wbuf++;
16690 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016692 /* Read rest of EEPROM not covered by the checksum. */
16693 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16694 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16695 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16696 if (*charfields++) {
16697 *wbuf = le16_to_cpu(*wbuf);
16698 }
16699 }
16700 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016701}
16702
16703/*
16704 * Read EEPROM configuration into the specified buffer.
16705 *
16706 * Return a checksum based on the EEPROM configuration read.
16707 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016708static ushort __init
16709AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016710{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016711 ushort wval, chksum;
16712 ushort *wbuf;
16713 int eep_addr;
16714 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016715
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016716 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16717 wbuf = (ushort *)cfg_buf;
16718 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016720 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16721 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16722 wval = AdvReadEEPWord(iop_base, eep_addr);
16723 chksum += wval; /* Checksum is calculated from word values. */
16724 if (*charfields++) {
16725 *wbuf = le16_to_cpu(wval);
16726 } else {
16727 *wbuf = wval;
16728 }
16729 }
16730 /* Read checksum word. */
16731 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16732 wbuf++;
16733 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016734
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016735 /* Read rest of EEPROM not covered by the checksum. */
16736 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16737 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16738 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16739 if (*charfields++) {
16740 *wbuf = le16_to_cpu(*wbuf);
16741 }
16742 }
16743 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016744}
16745
16746/*
16747 * Read EEPROM configuration into the specified buffer.
16748 *
16749 * Return a checksum based on the EEPROM configuration read.
16750 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016751static ushort __init
16752AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016753{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016754 ushort wval, chksum;
16755 ushort *wbuf;
16756 int eep_addr;
16757 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016758
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016759 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16760 wbuf = (ushort *)cfg_buf;
16761 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016762
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016763 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16764 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16765 wval = AdvReadEEPWord(iop_base, eep_addr);
16766 chksum += wval; /* Checksum is calculated from word values. */
16767 if (*charfields++) {
16768 *wbuf = le16_to_cpu(wval);
16769 } else {
16770 *wbuf = wval;
16771 }
16772 }
16773 /* Read checksum word. */
16774 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16775 wbuf++;
16776 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016777
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016778 /* Read rest of EEPROM not covered by the checksum. */
16779 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16780 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16781 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16782 if (*charfields++) {
16783 *wbuf = le16_to_cpu(*wbuf);
16784 }
16785 }
16786 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016787}
16788
16789/*
16790 * Read the EEPROM from specified location
16791 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016792static ushort __init AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016793{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016794 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16795 ASC_EEP_CMD_READ | eep_word_addr);
16796 AdvWaitEEPCmd(iop_base);
16797 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016798}
16799
16800/*
16801 * Wait for EEPROM command to complete
16802 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016803static void __init AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016804{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016805 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016807 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16808 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16809 ASC_EEP_CMD_DONE) {
16810 break;
16811 }
16812 DvcSleepMilliSecond(1);
16813 }
16814 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16815 0) {
16816 ASC_ASSERT(0);
16817 }
16818 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016819}
16820
16821/*
16822 * Write the EEPROM from 'cfg_buf'.
16823 */
Randy Dunlapc8360432006-06-25 05:48:40 -070016824void __init
Linus Torvalds1da177e2005-04-16 15:20:36 -070016825AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16826{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016827 ushort *wbuf;
16828 ushort addr, chksum;
16829 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016830
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016831 wbuf = (ushort *)cfg_buf;
16832 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16833 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016834
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016835 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16836 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016837
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016838 /*
16839 * Write EEPROM from word 0 to word 20.
16840 */
16841 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16842 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16843 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016844
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016845 if (*charfields++) {
16846 word = cpu_to_le16(*wbuf);
16847 } else {
16848 word = *wbuf;
16849 }
16850 chksum += *wbuf; /* Checksum is calculated from word values. */
16851 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16852 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16853 ASC_EEP_CMD_WRITE | addr);
16854 AdvWaitEEPCmd(iop_base);
16855 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016857
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016858 /*
16859 * Write EEPROM checksum at word 21.
16860 */
16861 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16862 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16863 AdvWaitEEPCmd(iop_base);
16864 wbuf++;
16865 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016866
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016867 /*
16868 * Write EEPROM OEM name at words 22 to 29.
16869 */
16870 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16871 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16872 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016873
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016874 if (*charfields++) {
16875 word = cpu_to_le16(*wbuf);
16876 } else {
16877 word = *wbuf;
16878 }
16879 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16880 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16881 ASC_EEP_CMD_WRITE | addr);
16882 AdvWaitEEPCmd(iop_base);
16883 }
16884 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16885 AdvWaitEEPCmd(iop_base);
16886 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016887}
16888
16889/*
16890 * Write the EEPROM from 'cfg_buf'.
16891 */
Randy Dunlapc8360432006-06-25 05:48:40 -070016892void __init
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016893AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016894{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016895 ushort *wbuf;
16896 ushort *charfields;
16897 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016898
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016899 wbuf = (ushort *)cfg_buf;
16900 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16901 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016902
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016903 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16904 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016905
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016906 /*
16907 * Write EEPROM from word 0 to word 20.
16908 */
16909 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16910 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16911 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016912
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016913 if (*charfields++) {
16914 word = cpu_to_le16(*wbuf);
16915 } else {
16916 word = *wbuf;
16917 }
16918 chksum += *wbuf; /* Checksum is calculated from word values. */
16919 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16920 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16921 ASC_EEP_CMD_WRITE | addr);
16922 AdvWaitEEPCmd(iop_base);
16923 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016925
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016926 /*
16927 * Write EEPROM checksum at word 21.
16928 */
16929 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16930 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16931 AdvWaitEEPCmd(iop_base);
16932 wbuf++;
16933 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016934
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016935 /*
16936 * Write EEPROM OEM name at words 22 to 29.
16937 */
16938 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16939 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16940 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016941
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016942 if (*charfields++) {
16943 word = cpu_to_le16(*wbuf);
16944 } else {
16945 word = *wbuf;
16946 }
16947 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16948 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16949 ASC_EEP_CMD_WRITE | addr);
16950 AdvWaitEEPCmd(iop_base);
16951 }
16952 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16953 AdvWaitEEPCmd(iop_base);
16954 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016955}
16956
16957/*
16958 * Write the EEPROM from 'cfg_buf'.
16959 */
Randy Dunlapc8360432006-06-25 05:48:40 -070016960void __init
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016961AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016962{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016963 ushort *wbuf;
16964 ushort *charfields;
16965 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016966
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016967 wbuf = (ushort *)cfg_buf;
16968 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16969 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016970
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016971 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16972 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016973
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016974 /*
16975 * Write EEPROM from word 0 to word 20.
16976 */
16977 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16978 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16979 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016980
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016981 if (*charfields++) {
16982 word = cpu_to_le16(*wbuf);
16983 } else {
16984 word = *wbuf;
16985 }
16986 chksum += *wbuf; /* Checksum is calculated from word values. */
16987 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16988 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16989 ASC_EEP_CMD_WRITE | addr);
16990 AdvWaitEEPCmd(iop_base);
16991 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016993
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016994 /*
16995 * Write EEPROM checksum at word 21.
16996 */
16997 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16998 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16999 AdvWaitEEPCmd(iop_base);
17000 wbuf++;
17001 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017002
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017003 /*
17004 * Write EEPROM OEM name at words 22 to 29.
17005 */
17006 for (addr = ADV_EEP_DVC_CTL_BEGIN;
17007 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
17008 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017009
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017010 if (*charfields++) {
17011 word = cpu_to_le16(*wbuf);
17012 } else {
17013 word = *wbuf;
17014 }
17015 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
17016 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
17017 ASC_EEP_CMD_WRITE | addr);
17018 AdvWaitEEPCmd(iop_base);
17019 }
17020 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
17021 AdvWaitEEPCmd(iop_base);
17022 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017023}
17024
17025/* a_advlib.c */
17026/*
17027 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
17028 *
17029 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
17030 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
17031 * RISC to notify it a new command is ready to be executed.
17032 *
17033 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
17034 * set to SCSI_MAX_RETRY.
17035 *
17036 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
17037 * for DMA addresses or math operations are byte swapped to little-endian
17038 * order.
17039 *
17040 * Return:
17041 * ADV_SUCCESS(1) - The request was successfully queued.
17042 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
17043 * request completes.
17044 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
17045 * host IC error.
17046 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017047static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017048{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017049 ulong last_int_level;
17050 AdvPortAddr iop_base;
17051 ADV_DCNT req_size;
17052 ADV_PADDR req_paddr;
17053 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017054
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017055 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017056
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017057 /*
17058 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
17059 */
17060 if (scsiq->target_id > ADV_MAX_TID) {
17061 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
17062 scsiq->done_status = QD_WITH_ERROR;
17063 return ADV_ERROR;
17064 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017065
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017066 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017067
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017068 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017069
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017070 /*
17071 * Allocate a carrier ensuring at least one carrier always
17072 * remains on the freelist and initialize fields.
17073 */
17074 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
17075 DvcLeaveCritical(last_int_level);
17076 return ADV_BUSY;
17077 }
17078 asc_dvc->carr_freelist = (ADV_CARR_T *)
17079 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
17080 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017081
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017082 /*
17083 * Set the carrier to be a stopper by setting 'next_vpa'
17084 * to the stopper value. The current stopper will be changed
17085 * below to point to the new stopper.
17086 */
17087 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017089 /*
17090 * Clear the ADV_SCSI_REQ_Q done flag.
17091 */
17092 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017094 req_size = sizeof(ADV_SCSI_REQ_Q);
17095 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
17096 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017097
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017098 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
17099 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017100
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017101 /* Wait for assertion before making little-endian */
17102 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017103
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017104 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
17105 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
17106 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017107
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017108 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
17109 /*
17110 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
17111 * order during initialization.
17112 */
17113 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017114
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017115 /*
17116 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
17117 * the microcode. The newly allocated stopper will become the new
17118 * stopper.
17119 */
17120 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017121
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017122 /*
17123 * Set the 'next_vpa' pointer for the old stopper to be the
17124 * physical address of the new stopper. The RISC can only
17125 * follow physical addresses.
17126 */
17127 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017128
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017129 /*
17130 * Set the host adapter stopper pointer to point to the new carrier.
17131 */
17132 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017133
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017134 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
17135 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17136 /*
17137 * Tickle the RISC to tell it to read its Command Queue Head pointer.
17138 */
17139 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
17140 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17141 /*
17142 * Clear the tickle value. In the ASC-3550 the RISC flag
17143 * command 'clr_tickle_a' does not work unless the host
17144 * value is cleared.
17145 */
17146 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
17147 ADV_TICKLE_NOP);
17148 }
17149 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17150 /*
17151 * Notify the RISC a carrier is ready by writing the physical
17152 * address of the new carrier stopper to the COMMA register.
17153 */
17154 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
17155 le32_to_cpu(new_carrp->carr_pa));
17156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017157
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017158 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017159
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017160 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017161}
17162
17163/*
17164 * Reset SCSI Bus and purge all outstanding requests.
17165 *
17166 * Return Value:
17167 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
17168 * ADV_FALSE(0) - Microcode command failed.
17169 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
17170 * may be hung which requires driver recovery.
17171 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017172static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017173{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017174 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017176 /*
17177 * Send the SCSI Bus Reset idle start idle command which asserts
17178 * the SCSI Bus Reset signal.
17179 */
17180 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
17181 if (status != ADV_TRUE) {
17182 return status;
17183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017184
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017185 /*
17186 * Delay for the specified SCSI Bus Reset hold time.
17187 *
17188 * The hold time delay is done on the host because the RISC has no
17189 * microsecond accurate timer.
17190 */
17191 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017192
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017193 /*
17194 * Send the SCSI Bus Reset end idle command which de-asserts
17195 * the SCSI Bus Reset signal and purges any pending requests.
17196 */
17197 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
17198 if (status != ADV_TRUE) {
17199 return status;
17200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017201
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017202 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017203
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017204 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017205}
17206
17207/*
17208 * Reset chip and SCSI Bus.
17209 *
17210 * Return Value:
17211 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
17212 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
17213 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017214static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017215{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017216 int status;
17217 ushort wdtr_able, sdtr_able, tagqng_able;
17218 ushort ppr_able = 0;
17219 uchar tid, max_cmd[ADV_MAX_TID + 1];
17220 AdvPortAddr iop_base;
17221 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017222
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017223 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017224
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017225 /*
17226 * Save current per TID negotiated values.
17227 */
17228 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
17229 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
17230 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17231 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
17232 }
17233 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
17234 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
17235 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
17236 max_cmd[tid]);
17237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017238
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017239 /*
17240 * Force the AdvInitAsc3550/38C0800Driver() function to
17241 * perform a SCSI Bus Reset by clearing the BIOS signature word.
17242 * The initialization functions assumes a SCSI Bus Reset is not
17243 * needed if the BIOS signature word is present.
17244 */
17245 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
17246 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017247
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017248 /*
17249 * Stop chip and reset it.
17250 */
17251 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
17252 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
17253 DvcSleepMilliSecond(100);
17254 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
17255 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017256
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017257 /*
17258 * Reset Adv Library error code, if any, and try
17259 * re-initializing the chip.
17260 */
17261 asc_dvc->err_code = 0;
17262 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17263 status = AdvInitAsc38C1600Driver(asc_dvc);
17264 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17265 status = AdvInitAsc38C0800Driver(asc_dvc);
17266 } else {
17267 status = AdvInitAsc3550Driver(asc_dvc);
17268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017269
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017270 /* Translate initialization return value to status value. */
17271 if (status == 0) {
17272 status = ADV_TRUE;
17273 } else {
17274 status = ADV_FALSE;
17275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017276
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017277 /*
17278 * Restore the BIOS signature word.
17279 */
17280 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017281
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017282 /*
17283 * Restore per TID negotiated values.
17284 */
17285 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
17286 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
17287 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17288 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
17289 }
17290 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
17291 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
17292 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
17293 max_cmd[tid]);
17294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017295
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017296 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017297}
17298
17299/*
17300 * Adv Library Interrupt Service Routine
17301 *
17302 * This function is called by a driver's interrupt service routine.
17303 * The function disables and re-enables interrupts.
17304 *
17305 * When a microcode idle command is completed, the ADV_DVC_VAR
17306 * 'idle_cmd_done' field is set to ADV_TRUE.
17307 *
17308 * Note: AdvISR() can be called when interrupts are disabled or even
17309 * when there is no hardware interrupt condition present. It will
17310 * always check for completed idle commands and microcode requests.
17311 * This is an important feature that shouldn't be changed because it
17312 * allows commands to be completed from polling mode loops.
17313 *
17314 * Return:
17315 * ADV_TRUE(1) - interrupt was pending
17316 * ADV_FALSE(0) - no interrupt was pending
17317 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017318static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017319{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017320 AdvPortAddr iop_base;
17321 uchar int_stat;
17322 ushort target_bit;
17323 ADV_CARR_T *free_carrp;
17324 ADV_VADDR irq_next_vpa;
17325 int flags;
17326 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017327
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017328 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017329
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017330 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017331
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017332 /* Reading the register clears the interrupt. */
17333 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017334
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017335 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
17336 ADV_INTR_STATUS_INTRC)) == 0) {
17337 DvcLeaveCritical(flags);
17338 return ADV_FALSE;
17339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017340
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017341 /*
17342 * Notify the driver of an asynchronous microcode condition by
17343 * calling the ADV_DVC_VAR.async_callback function. The function
17344 * is passed the microcode ASC_MC_INTRB_CODE byte value.
17345 */
17346 if (int_stat & ADV_INTR_STATUS_INTRB) {
17347 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017348
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017349 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017350
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017351 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
17352 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17353 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
17354 asc_dvc->carr_pending_cnt != 0) {
17355 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
17356 ADV_TICKLE_A);
17357 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17358 AdvWriteByteRegister(iop_base,
17359 IOPB_TICKLE,
17360 ADV_TICKLE_NOP);
17361 }
17362 }
17363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017364
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017365 if (asc_dvc->async_callback != 0) {
17366 (*asc_dvc->async_callback) (asc_dvc, intrb_code);
17367 }
17368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017369
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017370 /*
17371 * Check if the IRQ stopper carrier contains a completed request.
17372 */
17373 while (((irq_next_vpa =
17374 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
17375 /*
17376 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
17377 * The RISC will have set 'areq_vpa' to a virtual address.
17378 *
17379 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
17380 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
17381 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
17382 * in AdvExeScsiQueue().
17383 */
17384 scsiq = (ADV_SCSI_REQ_Q *)
17385 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017386
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017387 /*
17388 * Request finished with good status and the queue was not
17389 * DMAed to host memory by the firmware. Set all status fields
17390 * to indicate good status.
17391 */
17392 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
17393 scsiq->done_status = QD_NO_ERROR;
17394 scsiq->host_status = scsiq->scsi_status = 0;
17395 scsiq->data_cnt = 0L;
17396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017397
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017398 /*
17399 * Advance the stopper pointer to the next carrier
17400 * ignoring the lower four bits. Free the previous
17401 * stopper carrier.
17402 */
17403 free_carrp = asc_dvc->irq_sp;
17404 asc_dvc->irq_sp = (ADV_CARR_T *)
17405 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017406
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017407 free_carrp->next_vpa =
17408 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
17409 asc_dvc->carr_freelist = free_carrp;
17410 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017411
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017412 ASC_ASSERT(scsiq != NULL);
17413 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017414
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017415 /*
17416 * Clear request microcode control flag.
17417 */
17418 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017419
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017420 /*
17421 * If the command that completed was a SCSI INQUIRY and
17422 * LUN 0 was sent the command, then process the INQUIRY
17423 * command information for the device.
17424 *
17425 * Note: If data returned were either VPD or CmdDt data,
17426 * don't process the INQUIRY command information for
17427 * the device, otherwise may erroneously set *_able bits.
17428 */
17429 if (scsiq->done_status == QD_NO_ERROR &&
17430 scsiq->cdb[0] == INQUIRY &&
17431 scsiq->target_lun == 0 &&
17432 (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
17433 == ADV_INQ_RTN_STD_INQUIRY_DATA) {
17434 AdvInquiryHandling(asc_dvc, scsiq);
17435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017436
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017437 /*
17438 * Notify the driver of the completed request by passing
17439 * the ADV_SCSI_REQ_Q pointer to its callback function.
17440 */
17441 scsiq->a_flag |= ADV_SCSIQ_DONE;
17442 (*asc_dvc->isr_callback) (asc_dvc, scsiq);
17443 /*
17444 * Note: After the driver callback function is called, 'scsiq'
17445 * can no longer be referenced.
17446 *
17447 * Fall through and continue processing other completed
17448 * requests...
17449 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017450
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017451 /*
17452 * Disable interrupts again in case the driver inadvertently
17453 * enabled interrupts in its callback function.
17454 *
17455 * The DvcEnterCritical() return value is ignored, because
17456 * the 'flags' saved when AdvISR() was first entered will be
17457 * used to restore the interrupt flag on exit.
17458 */
17459 (void)DvcEnterCritical();
17460 }
17461 DvcLeaveCritical(flags);
17462 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017463}
17464
17465/*
17466 * Send an idle command to the chip and wait for completion.
17467 *
17468 * Command completion is polled for once per microsecond.
17469 *
17470 * The function can be called from anywhere including an interrupt handler.
17471 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
17472 * functions to prevent reentrancy.
17473 *
17474 * Return Values:
17475 * ADV_TRUE - command completed successfully
17476 * ADV_FALSE - command failed
17477 * ADV_ERROR - command timed out
17478 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017479static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070017480AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017481 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017482{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017483 ulong last_int_level;
17484 int result;
17485 ADV_DCNT i, j;
17486 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017487
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017488 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017489
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017490 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017491
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017492 /*
17493 * Clear the idle command status which is set by the microcode
17494 * to a non-zero value to indicate when the command is completed.
17495 * The non-zero result is one of the IDLE_CMD_STATUS_* values
17496 * defined in a_advlib.h.
17497 */
17498 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017499
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017500 /*
17501 * Write the idle command value after the idle command parameter
17502 * has been written to avoid a race condition. If the order is not
17503 * followed, the microcode may process the idle command before the
17504 * parameters have been written to LRAM.
17505 */
17506 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
17507 cpu_to_le32(idle_cmd_parameter));
17508 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017509
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017510 /*
17511 * Tickle the RISC to tell it to process the idle command.
17512 */
17513 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
17514 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17515 /*
17516 * Clear the tickle value. In the ASC-3550 the RISC flag
17517 * command 'clr_tickle_b' does not work unless the host
17518 * value is cleared.
17519 */
17520 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
17521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017522
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017523 /* Wait for up to 100 millisecond for the idle command to timeout. */
17524 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
17525 /* Poll once each microsecond for command completion. */
17526 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
17527 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
17528 result);
17529 if (result != 0) {
17530 DvcLeaveCritical(last_int_level);
17531 return result;
17532 }
17533 DvcDelayMicroSecond(asc_dvc, (ushort)1);
17534 }
17535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017536
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017537 ASC_ASSERT(0); /* The idle command should never timeout. */
17538 DvcLeaveCritical(last_int_level);
17539 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017540}
17541
17542/*
17543 * Inquiry Information Byte 7 Handling
17544 *
17545 * Handle SCSI Inquiry Command information for a device by setting
17546 * microcode operating variables that affect WDTR, SDTR, and Tag
17547 * Queuing.
17548 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017549static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017550{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017551 AdvPortAddr iop_base;
17552 uchar tid;
17553 ADV_SCSI_INQUIRY *inq;
17554 ushort tidmask;
17555 ushort cfg_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017556
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017557 /*
17558 * AdvInquiryHandling() requires up to INQUIRY information Byte 7
17559 * to be available.
17560 *
17561 * If less than 8 bytes of INQUIRY information were requested or less
17562 * than 8 bytes were transferred, then return. cdb[4] is the request
17563 * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
17564 * microcode to the transfer residual count.
17565 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017566
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017567 if (scsiq->cdb[4] < 8 ||
17568 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) {
17569 return;
17570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017571
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017572 iop_base = asc_dvc->iop_base;
17573 tid = scsiq->target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017575 inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017577 /*
17578 * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
17579 */
17580 if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) {
17581 return;
17582 } else {
17583 /*
17584 * INQUIRY Byte 7 Handling
17585 *
17586 * Use a device's INQUIRY byte 7 to determine whether it
17587 * supports WDTR, SDTR, and Tag Queuing. If the feature
17588 * is enabled in the EEPROM and the device supports the
17589 * feature, then enable it in the microcode.
17590 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017591
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017592 tidmask = ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017593
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017594 /*
17595 * Wide Transfers
17596 *
17597 * If the EEPROM enabled WDTR for the device and the device
17598 * supports wide bus (16 bit) transfers, then turn on the
17599 * device's 'wdtr_able' bit and write the new value to the
17600 * microcode.
17601 */
17602 if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) {
17603 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
17604 if ((cfg_word & tidmask) == 0) {
17605 cfg_word |= tidmask;
17606 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
17607 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017608
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017609 /*
17610 * Clear the microcode "SDTR negotiation" and "WDTR
17611 * negotiation" done indicators for the target to cause
17612 * it to negotiate with the new setting set above.
17613 * WDTR when accepted causes the target to enter
17614 * asynchronous mode, so SDTR must be negotiated.
17615 */
17616 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17617 cfg_word);
17618 cfg_word &= ~tidmask;
17619 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17620 cfg_word);
17621 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE,
17622 cfg_word);
17623 cfg_word &= ~tidmask;
17624 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE,
17625 cfg_word);
17626 }
17627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017629 /*
17630 * Synchronous Transfers
17631 *
17632 * If the EEPROM enabled SDTR for the device and the device
17633 * supports synchronous transfers, then turn on the device's
17634 * 'sdtr_able' bit. Write the new value to the microcode.
17635 */
17636 if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) {
17637 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
17638 if ((cfg_word & tidmask) == 0) {
17639 cfg_word |= tidmask;
17640 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
17641 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017643 /*
17644 * Clear the microcode "SDTR negotiation" done indicator
17645 * for the target to cause it to negotiate with the new
17646 * setting set above.
17647 */
17648 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17649 cfg_word);
17650 cfg_word &= ~tidmask;
17651 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17652 cfg_word);
17653 }
17654 }
17655 /*
17656 * If the Inquiry data included enough space for the SPI-3
17657 * Clocking field, then check if DT mode is supported.
17658 */
17659 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
17660 (scsiq->cdb[4] >= 57 ||
17661 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) {
17662 /*
17663 * PPR (Parallel Protocol Request) Capable
17664 *
17665 * If the device supports DT mode, then it must be PPR capable.
17666 * The PPR message will be used in place of the SDTR and WDTR
17667 * messages to negotiate synchronous speed and offset, transfer
17668 * width, and protocol options.
17669 */
17670 if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) {
17671 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE,
17672 asc_dvc->ppr_able);
17673 asc_dvc->ppr_able |= tidmask;
17674 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE,
17675 asc_dvc->ppr_able);
17676 }
17677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017678
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017679 /*
17680 * If the EEPROM enabled Tag Queuing for the device and the
17681 * device supports Tag Queueing, then turn on the device's
17682 * 'tagqng_enable' bit in the microcode and set the microcode
17683 * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
17684 * value.
17685 *
17686 * Tag Queuing is disabled for the BIOS which runs in polled
17687 * mode and would see no benefit from Tag Queuing. Also by
17688 * disabling Tag Queuing in the BIOS devices with Tag Queuing
17689 * bugs will at least work with the BIOS.
17690 */
17691 if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) {
17692 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
17693 cfg_word |= tidmask;
17694 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
17695 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017696
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017697 AdvWriteByteLram(iop_base,
17698 ASC_MC_NUMBER_OF_MAX_CMD + tid,
17699 asc_dvc->max_dvc_qng);
17700 }
17701 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017702}
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017703
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017704static int __devinit
17705advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
17706{
17707 int req_cnt = 0;
17708 adv_req_t *reqp = NULL;
17709 int sg_cnt = 0;
17710 adv_sgblk_t *sgp;
17711 int warn_code, err_code;
17712
17713 /*
17714 * Allocate buffer carrier structures. The total size
17715 * is about 4 KB, so allocate all at once.
17716 */
17717 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
17718 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
17719
17720 if (!boardp->carrp)
17721 goto kmalloc_failed;
17722
17723 /*
17724 * Allocate up to 'max_host_qng' request structures for the Wide
17725 * board. The total size is about 16 KB, so allocate all at once.
17726 * If the allocation fails decrement and try again.
17727 */
17728 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
17729 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
17730
17731 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
17732 "bytes %lu\n", reqp, req_cnt,
17733 (ulong)sizeof(adv_req_t) * req_cnt);
17734
17735 if (reqp)
17736 break;
17737 }
17738
17739 if (!reqp)
17740 goto kmalloc_failed;
17741
17742 boardp->orig_reqp = reqp;
17743
17744 /*
17745 * Allocate up to ADV_TOT_SG_BLOCK request structures for
17746 * the Wide board. Each structure is about 136 bytes.
17747 */
17748 boardp->adv_sgblkp = NULL;
17749 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
17750 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
17751
17752 if (!sgp)
17753 break;
17754
17755 sgp->next_sgblkp = boardp->adv_sgblkp;
17756 boardp->adv_sgblkp = sgp;
17757
17758 }
17759
17760 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
17761 sg_cnt, sizeof(adv_sgblk_t),
17762 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
17763
17764 if (!boardp->adv_sgblkp)
17765 goto kmalloc_failed;
17766
17767 adv_dvc_varp->carrier_buf = boardp->carrp;
17768
17769 /*
17770 * Point 'adv_reqp' to the request structures and
17771 * link them together.
17772 */
17773 req_cnt--;
17774 reqp[req_cnt].next_reqp = NULL;
17775 for (; req_cnt > 0; req_cnt--) {
17776 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
17777 }
17778 boardp->adv_reqp = &reqp[0];
17779
17780 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17781 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
17782 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
17783 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17784 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
17785 "\n");
17786 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
17787 } else {
17788 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
17789 "\n");
17790 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
17791 }
17792 err_code = adv_dvc_varp->err_code;
17793
17794 if (warn_code || err_code) {
17795 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
17796 " error 0x%x\n", boardp->id, warn_code, err_code);
17797 }
17798
17799 goto exit;
17800
17801 kmalloc_failed:
17802 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
17803 "failed\n", boardp->id);
17804 err_code = ADV_ERROR;
17805 exit:
17806 return err_code;
17807}
17808
17809static void advansys_wide_free_mem(asc_board_t *boardp)
17810{
17811 kfree(boardp->carrp);
17812 boardp->carrp = NULL;
17813 kfree(boardp->orig_reqp);
17814 boardp->orig_reqp = boardp->adv_reqp = NULL;
17815 while (boardp->adv_sgblkp) {
17816 adv_sgblk_t *sgp = boardp->adv_sgblkp;
17817 boardp->adv_sgblkp = sgp->next_sgblkp;
17818 kfree(sgp);
17819 }
17820}
17821
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017822static struct Scsi_Host *__devinit
17823advansys_board_found(int iop, struct device *dev, int bus_type)
17824{
17825 struct Scsi_Host *shost;
17826 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
17827 asc_board_t *boardp;
17828 ASC_DVC_VAR *asc_dvc_varp = NULL;
17829 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017830 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017831 int iolen = 0;
17832 ADV_PADDR pci_memory_address;
17833 int warn_code, err_code;
17834 int ret;
17835
17836 /*
17837 * Adapter found.
17838 *
17839 * Register the adapter, get its configuration, and
17840 * initialize it.
17841 */
17842 ASC_DBG(2, "advansys_board_found: scsi_register()\n");
17843 shost = scsi_register(&driver_template, sizeof(asc_board_t));
17844
17845 if (!shost)
17846 return NULL;
17847
17848 /* Save a pointer to the Scsi_Host of each board found. */
17849 asc_host[asc_board_count++] = shost;
17850
17851 /* Initialize private per board data */
17852 boardp = ASC_BOARDP(shost);
17853 memset(boardp, 0, sizeof(asc_board_t));
17854 boardp->id = asc_board_count - 1;
17855
17856 /* Initialize spinlock. */
17857 spin_lock_init(&boardp->lock);
17858
17859 /*
17860 * Handle both narrow and wide boards.
17861 *
17862 * If a Wide board was detected, set the board structure
17863 * wide board flag. Set-up the board structure based on
17864 * the board type.
17865 */
17866#ifdef CONFIG_PCI
17867 if (bus_type == ASC_IS_PCI &&
17868 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17869 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17870 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17871 boardp->flags |= ASC_IS_WIDE_BOARD;
17872 }
17873#endif /* CONFIG_PCI */
17874
17875 if (ASC_NARROW_BOARD(boardp)) {
17876 ASC_DBG(1, "advansys_board_found: narrow board\n");
17877 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17878 asc_dvc_varp->bus_type = bus_type;
17879 asc_dvc_varp->drv_ptr = boardp;
17880 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17881 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17882 asc_dvc_varp->iop_base = iop;
17883 asc_dvc_varp->isr_callback = asc_isr_callback;
17884 } else {
17885 ASC_DBG(1, "advansys_board_found: wide board\n");
17886 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17887 adv_dvc_varp->drv_ptr = boardp;
17888 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
17889 adv_dvc_varp->isr_callback = adv_isr_callback;
17890 adv_dvc_varp->async_callback = adv_async_callback;
17891#ifdef CONFIG_PCI
17892 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17893 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17894 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17895 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17896 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17897 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17898 } else {
17899 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17900 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17901 }
17902#endif /* CONFIG_PCI */
17903
17904 /*
17905 * Map the board's registers into virtual memory for
17906 * PCI slave access. Only memory accesses are used to
17907 * access the board's registers.
17908 *
17909 * Note: The PCI register base address is not always
17910 * page aligned, but the address passed to ioremap()
17911 * must be page aligned. It is guaranteed that the
17912 * PCI register base address will not cross a page
17913 * boundary.
17914 */
17915 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17916 iolen = ADV_3550_IOLEN;
17917 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17918 iolen = ADV_38C0800_IOLEN;
17919 } else {
17920 iolen = ADV_38C1600_IOLEN;
17921 }
17922#ifdef CONFIG_PCI
17923 pci_memory_address = pci_resource_start(pdev, 1);
17924 ASC_DBG1(1,
17925 "advansys_board_found: pci_memory_address: 0x%lx\n",
17926 (ulong)pci_memory_address);
17927 if ((boardp->ioremap_addr =
17928 ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
17929 ASC_PRINT3
17930 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
17931 boardp->id, pci_memory_address, iolen);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017932 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017933 }
17934 ASC_DBG1(1,
17935 "advansys_board_found: ioremap_addr: 0x%lx\n",
17936 (ulong)boardp->ioremap_addr);
17937 adv_dvc_varp->iop_base = (AdvPortAddr)
17938 (boardp->ioremap_addr +
17939 (pci_memory_address - (pci_memory_address & PAGE_MASK)));
17940 ASC_DBG1(1,
17941 "advansys_board_found: iop_base: 0x%lx\n",
17942 adv_dvc_varp->iop_base);
17943#endif /* CONFIG_PCI */
17944
17945 /*
17946 * Even though it isn't used to access wide boards, other
17947 * than for the debug line below, save I/O Port address so
17948 * that it can be reported.
17949 */
17950 boardp->ioport = iop;
17951
17952 ASC_DBG2(1,
17953 "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
17954 (ushort)inp(iop + 1), (ushort)inpw(iop));
17955 }
17956
17957#ifdef CONFIG_PROC_FS
17958 /*
17959 * Allocate buffer for printing information from
17960 * /proc/scsi/advansys/[0...].
17961 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017962 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
17963 if (!boardp->prtbuf) {
17964 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
17965 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
17966 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017967 }
17968#endif /* CONFIG_PROC_FS */
17969
17970 if (ASC_NARROW_BOARD(boardp)) {
17971 asc_dvc_varp->cfg->dev = dev;
17972 /*
17973 * Set the board bus type and PCI IRQ before
17974 * calling AscInitGetConfig().
17975 */
17976 switch (asc_dvc_varp->bus_type) {
17977#ifdef CONFIG_ISA
17978 case ASC_IS_ISA:
17979 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017980 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017981 break;
17982 case ASC_IS_VL:
17983 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017984 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017985 break;
17986 case ASC_IS_EISA:
17987 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017988 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017989 break;
17990#endif /* CONFIG_ISA */
17991#ifdef CONFIG_PCI
17992 case ASC_IS_PCI:
17993 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
17994 asc_dvc_varp->cfg->pci_slot_info =
17995 ASC_PCI_MKID(pdev->bus->number,
17996 PCI_SLOT(pdev->devfn),
17997 PCI_FUNC(pdev->devfn));
17998 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017999 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018000 break;
18001#endif /* CONFIG_PCI */
18002 default:
18003 ASC_PRINT2
18004 ("advansys_board_found: board %d: unknown adapter type: %d\n",
18005 boardp->id, asc_dvc_varp->bus_type);
18006 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060018007 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018008 break;
18009 }
18010 } else {
18011 adv_dvc_varp->cfg->dev = dev;
18012 /*
18013 * For Wide boards set PCI information before calling
18014 * AdvInitGetConfig().
18015 */
18016#ifdef CONFIG_PCI
18017 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
18018 adv_dvc_varp->cfg->pci_slot_info =
18019 ASC_PCI_MKID(pdev->bus->number,
18020 PCI_SLOT(pdev->devfn),
18021 PCI_FUNC(pdev->devfn));
18022 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060018023 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018024#endif /* CONFIG_PCI */
18025 }
18026
18027 /*
18028 * Read the board configuration.
18029 */
18030 if (ASC_NARROW_BOARD(boardp)) {
18031 /*
18032 * NOTE: AscInitGetConfig() may change the board's
18033 * bus_type value. The bus_type value should no
18034 * longer be used. If the bus_type field must be
18035 * referenced only use the bit-wise AND operator "&".
18036 */
18037 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
18038 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
18039 case 0: /* No error */
18040 break;
18041 case ASC_WARN_IO_PORT_ROTATE:
18042 ASC_PRINT1
18043 ("AscInitGetConfig: board %d: I/O port address modified\n",
18044 boardp->id);
18045 break;
18046 case ASC_WARN_AUTO_CONFIG:
18047 ASC_PRINT1
18048 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
18049 boardp->id);
18050 break;
18051 case ASC_WARN_EEPROM_CHKSUM:
18052 ASC_PRINT1
18053 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
18054 boardp->id);
18055 break;
18056 case ASC_WARN_IRQ_MODIFIED:
18057 ASC_PRINT1
18058 ("AscInitGetConfig: board %d: IRQ modified\n",
18059 boardp->id);
18060 break;
18061 case ASC_WARN_CMD_QNG_CONFLICT:
18062 ASC_PRINT1
18063 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
18064 boardp->id);
18065 break;
18066 default:
18067 ASC_PRINT2
18068 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
18069 boardp->id, ret);
18070 break;
18071 }
18072 if ((err_code = asc_dvc_varp->err_code) != 0) {
18073 ASC_PRINT3
18074 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
18075 boardp->id,
18076 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
18077 }
18078 } else {
18079 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
18080 if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
18081 ASC_PRINT2
18082 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
18083 boardp->id, ret);
18084 }
18085 if ((err_code = adv_dvc_varp->err_code) != 0) {
18086 ASC_PRINT2
18087 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
18088 boardp->id, adv_dvc_varp->err_code);
18089 }
18090 }
18091
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018092 if (err_code != 0)
18093 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018094
18095 /*
18096 * Save the EEPROM configuration so that it can be displayed
18097 * from /proc/scsi/advansys/[0...].
18098 */
18099 if (ASC_NARROW_BOARD(boardp)) {
18100
18101 ASCEEP_CONFIG *ep;
18102
18103 /*
18104 * Set the adapter's target id bit in the 'init_tidmask' field.
18105 */
18106 boardp->init_tidmask |=
18107 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
18108
18109 /*
18110 * Save EEPROM settings for the board.
18111 */
18112 ep = &boardp->eep_config.asc_eep;
18113
18114 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
18115 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
18116 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
18117 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
18118 ep->start_motor = asc_dvc_varp->start_motor;
18119 ep->cntl = asc_dvc_varp->dvc_cntl;
18120 ep->no_scam = asc_dvc_varp->no_scam;
18121 ep->max_total_qng = asc_dvc_varp->max_total_qng;
18122 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
18123 /* 'max_tag_qng' is set to the same value for every device. */
18124 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
18125 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
18126 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
18127 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
18128 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
18129 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
18130 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
18131
18132 /*
18133 * Modify board configuration.
18134 */
18135 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
18136 switch (ret = AscInitSetConfig(asc_dvc_varp)) {
18137 case 0: /* No error. */
18138 break;
18139 case ASC_WARN_IO_PORT_ROTATE:
18140 ASC_PRINT1
18141 ("AscInitSetConfig: board %d: I/O port address modified\n",
18142 boardp->id);
18143 break;
18144 case ASC_WARN_AUTO_CONFIG:
18145 ASC_PRINT1
18146 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
18147 boardp->id);
18148 break;
18149 case ASC_WARN_EEPROM_CHKSUM:
18150 ASC_PRINT1
18151 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
18152 boardp->id);
18153 break;
18154 case ASC_WARN_IRQ_MODIFIED:
18155 ASC_PRINT1
18156 ("AscInitSetConfig: board %d: IRQ modified\n",
18157 boardp->id);
18158 break;
18159 case ASC_WARN_CMD_QNG_CONFLICT:
18160 ASC_PRINT1
18161 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
18162 boardp->id);
18163 break;
18164 default:
18165 ASC_PRINT2
18166 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
18167 boardp->id, ret);
18168 break;
18169 }
18170 if (asc_dvc_varp->err_code != 0) {
18171 ASC_PRINT3
18172 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
18173 boardp->id,
18174 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018175 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018176 }
18177
18178 /*
18179 * Finish initializing the 'Scsi_Host' structure.
18180 */
18181 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
18182 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
18183 shost->irq = asc_dvc_varp->irq_no;
18184 }
18185 } else {
18186 ADVEEP_3550_CONFIG *ep_3550;
18187 ADVEEP_38C0800_CONFIG *ep_38C0800;
18188 ADVEEP_38C1600_CONFIG *ep_38C1600;
18189
18190 /*
18191 * Save Wide EEP Configuration Information.
18192 */
18193 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
18194 ep_3550 = &boardp->eep_config.adv_3550_eep;
18195
18196 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
18197 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
18198 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18199 ep_3550->termination = adv_dvc_varp->cfg->termination;
18200 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
18201 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
18202 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
18203 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
18204 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
18205 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
18206 ep_3550->start_motor = adv_dvc_varp->start_motor;
18207 ep_3550->scsi_reset_delay =
18208 adv_dvc_varp->scsi_reset_wait;
18209 ep_3550->serial_number_word1 =
18210 adv_dvc_varp->cfg->serial1;
18211 ep_3550->serial_number_word2 =
18212 adv_dvc_varp->cfg->serial2;
18213 ep_3550->serial_number_word3 =
18214 adv_dvc_varp->cfg->serial3;
18215 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
18216 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
18217
18218 ep_38C0800->adapter_scsi_id =
18219 adv_dvc_varp->chip_scsi_id;
18220 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
18221 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18222 ep_38C0800->termination_lvd =
18223 adv_dvc_varp->cfg->termination;
18224 ep_38C0800->disc_enable =
18225 adv_dvc_varp->cfg->disc_enable;
18226 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
18227 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
18228 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
18229 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
18230 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
18231 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
18232 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
18233 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
18234 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
18235 ep_38C0800->scsi_reset_delay =
18236 adv_dvc_varp->scsi_reset_wait;
18237 ep_38C0800->serial_number_word1 =
18238 adv_dvc_varp->cfg->serial1;
18239 ep_38C0800->serial_number_word2 =
18240 adv_dvc_varp->cfg->serial2;
18241 ep_38C0800->serial_number_word3 =
18242 adv_dvc_varp->cfg->serial3;
18243 } else {
18244 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
18245
18246 ep_38C1600->adapter_scsi_id =
18247 adv_dvc_varp->chip_scsi_id;
18248 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
18249 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18250 ep_38C1600->termination_lvd =
18251 adv_dvc_varp->cfg->termination;
18252 ep_38C1600->disc_enable =
18253 adv_dvc_varp->cfg->disc_enable;
18254 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
18255 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
18256 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
18257 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
18258 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
18259 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
18260 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
18261 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
18262 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
18263 ep_38C1600->scsi_reset_delay =
18264 adv_dvc_varp->scsi_reset_wait;
18265 ep_38C1600->serial_number_word1 =
18266 adv_dvc_varp->cfg->serial1;
18267 ep_38C1600->serial_number_word2 =
18268 adv_dvc_varp->cfg->serial2;
18269 ep_38C1600->serial_number_word3 =
18270 adv_dvc_varp->cfg->serial3;
18271 }
18272
18273 /*
18274 * Set the adapter's target id bit in the 'init_tidmask' field.
18275 */
18276 boardp->init_tidmask |=
18277 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
18278
18279 /*
18280 * Finish initializing the 'Scsi_Host' structure.
18281 */
18282 shost->irq = adv_dvc_varp->irq_no;
18283 }
18284
18285 /*
18286 * Channels are numbered beginning with 0. For AdvanSys one host
18287 * structure supports one channel. Multi-channel boards have a
18288 * separate host structure for each channel.
18289 */
18290 shost->max_channel = 0;
18291 if (ASC_NARROW_BOARD(boardp)) {
18292 shost->max_id = ASC_MAX_TID + 1;
18293 shost->max_lun = ASC_MAX_LUN + 1;
18294
18295 shost->io_port = asc_dvc_varp->iop_base;
18296 boardp->asc_n_io_port = ASC_IOADR_GAP;
18297 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
18298
18299 /* Set maximum number of queues the adapter can handle. */
18300 shost->can_queue = asc_dvc_varp->max_total_qng;
18301 } else {
18302 shost->max_id = ADV_MAX_TID + 1;
18303 shost->max_lun = ADV_MAX_LUN + 1;
18304
18305 /*
18306 * Save the I/O Port address and length even though
18307 * I/O ports are not used to access Wide boards.
18308 * Instead the Wide boards are accessed with
18309 * PCI Memory Mapped I/O.
18310 */
18311 shost->io_port = iop;
18312 boardp->asc_n_io_port = iolen;
18313
18314 shost->this_id = adv_dvc_varp->chip_scsi_id;
18315
18316 /* Set maximum number of queues the adapter can handle. */
18317 shost->can_queue = adv_dvc_varp->max_host_qng;
18318 }
18319
18320 /*
18321 * 'n_io_port' currently is one byte.
18322 *
18323 * Set a value to 'n_io_port', but never referenced it because
18324 * it may be truncated.
18325 */
18326 shost->n_io_port = boardp->asc_n_io_port <= 255 ?
18327 boardp->asc_n_io_port : 255;
18328
18329 /*
18330 * Following v1.3.89, 'cmd_per_lun' is no longer needed
18331 * and should be set to zero.
18332 *
18333 * But because of a bug introduced in v1.3.89 if the driver is
18334 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
18335 * SCSI function 'allocate_device' will panic. To allow the driver
18336 * to work as a module in these kernels set 'cmd_per_lun' to 1.
18337 *
18338 * Note: This is wrong. cmd_per_lun should be set to the depth
18339 * you want on untagged devices always.
18340 #ifdef MODULE
18341 */
18342 shost->cmd_per_lun = 1;
18343/* #else
18344 shost->cmd_per_lun = 0;
18345#endif */
18346
18347 /*
18348 * Set the maximum number of scatter-gather elements the
18349 * adapter can handle.
18350 */
18351 if (ASC_NARROW_BOARD(boardp)) {
18352 /*
18353 * Allow two commands with 'sg_tablesize' scatter-gather
18354 * elements to be executed simultaneously. This value is
18355 * the theoretical hardware limit. It may be decreased
18356 * below.
18357 */
18358 shost->sg_tablesize =
18359 (((asc_dvc_varp->max_total_qng - 2) / 2) *
18360 ASC_SG_LIST_PER_Q) + 1;
18361 } else {
18362 shost->sg_tablesize = ADV_MAX_SG_LIST;
18363 }
18364
18365 /*
18366 * The value of 'sg_tablesize' can not exceed the SCSI
18367 * mid-level driver definition of SG_ALL. SG_ALL also
18368 * must not be exceeded, because it is used to define the
18369 * size of the scatter-gather table in 'struct asc_sg_head'.
18370 */
18371 if (shost->sg_tablesize > SG_ALL) {
18372 shost->sg_tablesize = SG_ALL;
18373 }
18374
18375 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
18376
18377 /* BIOS start address. */
18378 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018379 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
18380 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018381 } else {
18382 /*
18383 * Fill-in BIOS board variables. The Wide BIOS saves
18384 * information in LRAM that is used by the driver.
18385 */
18386 AdvReadWordLram(adv_dvc_varp->iop_base,
18387 BIOS_SIGNATURE, boardp->bios_signature);
18388 AdvReadWordLram(adv_dvc_varp->iop_base,
18389 BIOS_VERSION, boardp->bios_version);
18390 AdvReadWordLram(adv_dvc_varp->iop_base,
18391 BIOS_CODESEG, boardp->bios_codeseg);
18392 AdvReadWordLram(adv_dvc_varp->iop_base,
18393 BIOS_CODELEN, boardp->bios_codelen);
18394
18395 ASC_DBG2(1,
18396 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
18397 boardp->bios_signature, boardp->bios_version);
18398
18399 ASC_DBG2(1,
18400 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
18401 boardp->bios_codeseg, boardp->bios_codelen);
18402
18403 /*
18404 * If the BIOS saved a valid signature, then fill in
18405 * the BIOS code segment base address.
18406 */
18407 if (boardp->bios_signature == 0x55AA) {
18408 /*
18409 * Convert x86 realmode code segment to a linear
18410 * address by shifting left 4.
18411 */
18412 shost->base = ((ulong)boardp->bios_codeseg << 4);
18413 } else {
18414 shost->base = 0;
18415 }
18416 }
18417
18418 /*
18419 * Register Board Resources - I/O Port, DMA, IRQ
18420 */
18421
18422 /*
18423 * Register I/O port range.
18424 *
18425 * For Wide boards the I/O ports are not used to access
18426 * the board, but request the region anyway.
18427 *
18428 * 'shost->n_io_port' is not referenced, because it may be truncated.
18429 */
18430 ASC_DBG2(2,
18431 "advansys_board_found: request_region port 0x%lx, len 0x%x\n",
18432 (ulong)shost->io_port, boardp->asc_n_io_port);
18433 if (request_region(shost->io_port, boardp->asc_n_io_port,
18434 "advansys") == NULL) {
18435 ASC_PRINT3
18436 ("advansys_board_found: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
18437 boardp->id, (ulong)shost->io_port, boardp->asc_n_io_port);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018438 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018439 }
18440
18441 /* Register DMA Channel for Narrow boards. */
18442 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
18443#ifdef CONFIG_ISA
18444 if (ASC_NARROW_BOARD(boardp)) {
18445 /* Register DMA channel for ISA bus. */
18446 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
18447 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018448 ret = request_dma(shost->dma_channel, "advansys");
18449 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018450 ASC_PRINT3
18451 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
18452 boardp->id, shost->dma_channel, ret);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018453 goto err_free_region;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018454 }
18455 AscEnableIsaDma(shost->dma_channel);
18456 }
18457 }
18458#endif /* CONFIG_ISA */
18459
18460 /* Register IRQ Number. */
18461 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060018462
18463 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
18464 "advansys", shost);
18465
18466 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018467 if (ret == -EBUSY) {
18468 ASC_PRINT2
18469 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
18470 boardp->id, shost->irq);
18471 } else if (ret == -EINVAL) {
18472 ASC_PRINT2
18473 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
18474 boardp->id, shost->irq);
18475 } else {
18476 ASC_PRINT3
18477 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
18478 boardp->id, shost->irq, ret);
18479 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018480 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018481 }
18482
18483 /*
18484 * Initialize board RISC chip and enable interrupts.
18485 */
18486 if (ASC_NARROW_BOARD(boardp)) {
18487 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
18488 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
18489 err_code = asc_dvc_varp->err_code;
18490
18491 if (warn_code || err_code) {
18492 ASC_PRINT4
18493 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
18494 boardp->id,
18495 asc_dvc_varp->init_state, warn_code, err_code);
18496 }
18497 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018498 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018499 }
18500
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018501 if (err_code != 0)
18502 goto err_free_wide_mem;
18503
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018504 ASC_DBG_PRT_SCSI_HOST(2, shost);
18505
18506 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018507
18508 err_free_wide_mem:
18509 advansys_wide_free_mem(boardp);
18510 free_irq(shost->irq, shost);
18511 err_free_dma:
18512 if (shost->dma_channel != NO_ISA_DMA)
18513 free_dma(shost->dma_channel);
18514 err_free_region:
18515 release_region(shost->io_port, boardp->asc_n_io_port);
18516 err_free_proc:
18517 kfree(boardp->prtbuf);
18518 err_unmap:
18519 if (boardp->ioremap_addr)
18520 iounmap(boardp->ioremap_addr);
18521 err_shost:
18522 scsi_unregister(shost);
18523 asc_board_count--;
18524 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018525}
18526
18527/*
18528 * advansys_detect()
18529 *
18530 * Detect function for AdvanSys adapters.
18531 *
18532 * Argument is a pointer to the host driver's scsi_hosts entry.
18533 *
18534 * Return number of adapters found.
18535 *
18536 * Note: Because this function is called during system initialization
18537 * it must not call SCSI mid-level functions including scsi_malloc()
18538 * and scsi_free().
18539 */
18540static int __init advansys_detect(struct scsi_host_template *tpnt)
18541{
18542 static int detect_called = ASC_FALSE;
18543 int iop;
18544 int bus;
18545 int ioport = 0;
18546 struct device *dev = NULL;
18547#ifdef CONFIG_PCI
18548 int pci_init_search = 0;
18549 struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
18550 int pci_card_cnt_max = 0;
18551 int pci_card_cnt = 0;
18552 struct pci_dev *pdev = NULL;
18553 int pci_device_id_cnt = 0;
18554 unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
18555 PCI_DEVICE_ID_ASP_1200A,
18556 PCI_DEVICE_ID_ASP_ABP940,
18557 PCI_DEVICE_ID_ASP_ABP940U,
18558 PCI_DEVICE_ID_ASP_ABP940UW,
18559 PCI_DEVICE_ID_38C0800_REV1,
18560 PCI_DEVICE_ID_38C1600_REV1
18561 };
18562#endif /* CONFIG_PCI */
18563
18564 if (detect_called == ASC_FALSE) {
18565 detect_called = ASC_TRUE;
18566 } else {
18567 printk
18568 ("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
18569 return 0;
18570 }
18571
18572 ASC_DBG(1, "advansys_detect: begin\n");
18573
18574 asc_board_count = 0;
18575
18576 /*
18577 * If I/O port probing has been modified, then verify and
18578 * clean-up the 'asc_ioport' list.
18579 */
18580 if (asc_iopflag == ASC_TRUE) {
18581 for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
18582 ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
18583 ioport, asc_ioport[ioport]);
18584 if (asc_ioport[ioport] != 0) {
18585 for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX;
18586 iop++) {
18587 if (_asc_def_iop_base[iop] ==
18588 asc_ioport[ioport]) {
18589 break;
18590 }
18591 }
18592 if (iop == ASC_IOADR_TABLE_MAX_IX) {
18593 printk
18594 ("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
18595 asc_ioport[ioport]);
18596 asc_ioport[ioport] = 0;
18597 }
18598 }
18599 }
18600 ioport = 0;
18601 }
18602
18603 for (bus = 0; bus < ASC_NUM_BUS; bus++) {
18604
18605 ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
18606 bus, asc_bus_name[bus]);
18607 iop = 0;
18608
18609 while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
18610
18611 ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
18612 asc_board_count);
18613
18614 switch (asc_bus[bus]) {
18615 case ASC_IS_ISA:
18616 case ASC_IS_VL:
18617#ifdef CONFIG_ISA
18618 if (asc_iopflag == ASC_FALSE) {
18619 iop =
18620 AscSearchIOPortAddr(iop,
18621 asc_bus[bus]);
18622 } else {
18623 /*
18624 * ISA and VL I/O port scanning has either been
18625 * eliminated or limited to selected ports on
18626 * the LILO command line, /etc/lilo.conf, or
18627 * by setting variables when the module was loaded.
18628 */
18629 ASC_DBG(1,
18630 "advansys_detect: I/O port scanning modified\n");
18631 ioport_try_again:
18632 iop = 0;
18633 for (; ioport < ASC_NUM_IOPORT_PROBE;
18634 ioport++) {
18635 if ((iop =
18636 asc_ioport[ioport]) != 0) {
18637 break;
18638 }
18639 }
18640 if (iop) {
18641 ASC_DBG1(1,
18642 "advansys_detect: probing I/O port 0x%x...\n",
18643 iop);
18644 if (!request_region
18645 (iop, ASC_IOADR_GAP,
18646 "advansys")) {
18647 printk
18648 ("AdvanSys SCSI: specified I/O Port 0x%X is busy\n",
18649 iop);
18650 /* Don't try this I/O port twice. */
18651 asc_ioport[ioport] = 0;
18652 goto ioport_try_again;
18653 } else if (AscFindSignature(iop)
18654 == ASC_FALSE) {
18655 printk
18656 ("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n",
18657 iop);
18658 /* Don't try this I/O port twice. */
18659 release_region(iop,
18660 ASC_IOADR_GAP);
18661 asc_ioport[ioport] = 0;
18662 goto ioport_try_again;
18663 } else {
18664 /*
18665 * If this isn't an ISA board, then it must be
18666 * a VL board. If currently looking an ISA
18667 * board is being looked for then try for
18668 * another ISA board in 'asc_ioport'.
18669 */
18670 if (asc_bus[bus] ==
18671 ASC_IS_ISA
18672 &&
18673 (AscGetChipVersion
18674 (iop,
18675 ASC_IS_ISA) &
18676 ASC_CHIP_VER_ISA_BIT)
18677 == 0) {
18678 /*
18679 * Don't clear 'asc_ioport[ioport]'. Try
18680 * this board again for VL. Increment
18681 * 'ioport' past this board.
18682 */
18683 ioport++;
18684 release_region
18685 (iop,
18686 ASC_IOADR_GAP);
18687 goto ioport_try_again;
18688 }
18689 }
18690 /*
18691 * This board appears good, don't try the I/O port
18692 * again by clearing its value. Increment 'ioport'
18693 * for the next iteration.
18694 */
18695 asc_ioport[ioport++] = 0;
18696 }
18697 }
18698#endif /* CONFIG_ISA */
18699 break;
18700
18701 case ASC_IS_EISA:
18702#ifdef CONFIG_ISA
18703 iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
18704#endif /* CONFIG_ISA */
18705 break;
18706
18707 case ASC_IS_PCI:
18708#ifdef CONFIG_PCI
18709 if (pci_init_search == 0) {
18710 int i, j;
18711
18712 pci_init_search = 1;
18713
18714 /* Find all PCI cards. */
18715 while (pci_device_id_cnt <
18716 ASC_PCI_DEVICE_ID_CNT) {
18717 if ((pdev =
18718 pci_find_device
18719 (PCI_VENDOR_ID_ASP,
18720 pci_device_id
18721 [pci_device_id_cnt],
18722 pdev)) == NULL) {
18723 pci_device_id_cnt++;
18724 } else {
18725 if (pci_enable_device
18726 (pdev) == 0) {
18727 pci_devicep
18728 [pci_card_cnt_max++]
18729 = pdev;
18730 }
18731 }
18732 }
18733
18734 /*
18735 * Sort PCI cards in ascending order by PCI Bus, Slot,
18736 * and Device Number.
18737 */
18738 for (i = 0; i < pci_card_cnt_max - 1;
18739 i++) {
18740 for (j = i + 1;
18741 j < pci_card_cnt_max;
18742 j++) {
18743 if ((pci_devicep[j]->
18744 bus->number <
18745 pci_devicep[i]->
18746 bus->number)
18747 ||
18748 ((pci_devicep[j]->
18749 bus->number ==
18750 pci_devicep[i]->
18751 bus->number)
18752 &&
18753 (pci_devicep[j]->
18754 devfn <
18755 pci_devicep[i]->
18756 devfn))) {
18757 pdev =
18758 pci_devicep
18759 [i];
18760 pci_devicep[i] =
18761 pci_devicep
18762 [j];
18763 pci_devicep[j] =
18764 pdev;
18765 }
18766 }
18767 }
18768
18769 pci_card_cnt = 0;
18770 } else {
18771 pci_card_cnt++;
18772 }
18773
18774 if (pci_card_cnt == pci_card_cnt_max) {
18775 iop = 0;
18776 } else {
18777 pdev = pci_devicep[pci_card_cnt];
18778
18779 ASC_DBG2(2,
18780 "advansys_detect: devfn %d, bus number %d\n",
18781 pdev->devfn,
18782 pdev->bus->number);
18783 iop = pci_resource_start(pdev, 0);
18784 ASC_DBG2(1,
18785 "advansys_detect: vendorID %X, deviceID %X\n",
18786 pdev->vendor,
18787 pdev->device);
18788 ASC_DBG2(2,
18789 "advansys_detect: iop %X, irqLine %d\n",
18790 iop, pdev->irq);
18791 }
18792 if (pdev)
18793 dev = &pdev->dev;
18794
18795#endif /* CONFIG_PCI */
18796 break;
18797
18798 default:
18799 ASC_PRINT1
18800 ("advansys_detect: unknown bus type: %d\n",
18801 asc_bus[bus]);
18802 break;
18803 }
18804 ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
18805
18806 /*
18807 * Adapter not found, try next bus type.
18808 */
18809 if (iop == 0) {
18810 break;
18811 }
18812
18813 advansys_board_found(iop, dev, asc_bus[bus]);
18814 }
18815 }
18816
18817 ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n",
18818 asc_board_count);
18819 return asc_board_count;
18820}
18821
18822/*
18823 * advansys_release()
18824 *
18825 * Release resources allocated for a single AdvanSys adapter.
18826 */
18827static int advansys_release(struct Scsi_Host *shost)
18828{
18829 asc_board_t *boardp;
18830
18831 ASC_DBG(1, "advansys_release: begin\n");
18832 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060018833 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018834 if (shost->dma_channel != NO_ISA_DMA) {
18835 ASC_DBG(1, "advansys_release: free_dma()\n");
18836 free_dma(shost->dma_channel);
18837 }
18838 release_region(shost->io_port, boardp->asc_n_io_port);
18839 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018840 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018841 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018842 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018843 kfree(boardp->prtbuf);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018844 scsi_unregister(shost);
18845 ASC_DBG(1, "advansys_release: end\n");
18846 return 0;
18847}
18848
Randy Dunlapd8dafd82006-11-21 13:50:47 -080018849#ifdef CONFIG_PCI
Dave Jones2672ea82006-08-02 17:11:49 -040018850/* PCI Devices supported by this driver */
18851static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018852 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
18853 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18854 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
18855 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18856 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
18857 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18858 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
18859 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18860 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
18861 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18862 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
18863 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18864 {}
Dave Jones2672ea82006-08-02 17:11:49 -040018865};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018866
Dave Jones2672ea82006-08-02 17:11:49 -040018867MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Randy Dunlapd8dafd82006-11-21 13:50:47 -080018868#endif /* CONFIG_PCI */
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018869
18870MODULE_LICENSE("GPL");