blob: 3ba70323345df354b69cb0e10e644e64dc6d35d1 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
869#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
871#define ASC_DVCLIB_CALL_DONE (1)
872#define ASC_DVCLIB_CALL_FAILED (0)
873#define ASC_DVCLIB_CALL_ERROR (-1)
874
Dave Jones2672ea82006-08-02 17:11:49 -0400875#define PCI_VENDOR_ID_ASP 0x10cd
876#define PCI_DEVICE_ID_ASP_1200A 0x1100
877#define PCI_DEVICE_ID_ASP_ABP940 0x1200
878#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
879#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
880#define PCI_DEVICE_ID_38C0800_REV1 0x2500
881#define PCI_DEVICE_ID_38C1600_REV1 0x2700
882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883/*
884 * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
885 * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
886 * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
887 * SRB structure.
888 */
889#define CC_VERY_LONG_SG_LIST 0
890#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
891
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400892#define PortAddr unsigned short /* port address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893#define inp(port) inb(port)
894#define outp(port, byte) outb((byte), (port))
895
896#define inpw(port) inw(port)
897#define outpw(port, word) outw((word), (port))
898
899#define ASC_MAX_SG_QUEUE 7
900#define ASC_MAX_SG_LIST 255
901
902#define ASC_CS_TYPE unsigned short
903
904#define ASC_IS_ISA (0x0001)
905#define ASC_IS_ISAPNP (0x0081)
906#define ASC_IS_EISA (0x0002)
907#define ASC_IS_PCI (0x0004)
908#define ASC_IS_PCI_ULTRA (0x0104)
909#define ASC_IS_PCMCIA (0x0008)
910#define ASC_IS_MCA (0x0020)
911#define ASC_IS_VL (0x0040)
912#define ASC_ISA_PNP_PORT_ADDR (0x279)
913#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
914#define ASC_IS_WIDESCSI_16 (0x0100)
915#define ASC_IS_WIDESCSI_32 (0x0200)
916#define ASC_IS_BIG_ENDIAN (0x8000)
917#define ASC_CHIP_MIN_VER_VL (0x01)
918#define ASC_CHIP_MAX_VER_VL (0x07)
919#define ASC_CHIP_MIN_VER_PCI (0x09)
920#define ASC_CHIP_MAX_VER_PCI (0x0F)
921#define ASC_CHIP_VER_PCI_BIT (0x08)
922#define ASC_CHIP_MIN_VER_ISA (0x11)
923#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
924#define ASC_CHIP_MAX_VER_ISA (0x27)
925#define ASC_CHIP_VER_ISA_BIT (0x30)
926#define ASC_CHIP_VER_ISAPNP_BIT (0x20)
927#define ASC_CHIP_VER_ASYN_BUG (0x21)
928#define ASC_CHIP_VER_PCI 0x08
929#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02)
930#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03)
931#define ASC_CHIP_MIN_VER_EISA (0x41)
932#define ASC_CHIP_MAX_VER_EISA (0x47)
933#define ASC_CHIP_VER_EISA_BIT (0x40)
934#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
935#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21
936#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A
937#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL)
938#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
939#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL)
940#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
941#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL)
942#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
943#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
944#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
945
946#define ASC_SCSI_ID_BITS 3
947#define ASC_SCSI_TIX_TYPE uchar
948#define ASC_ALL_DEVICE_BIT_SET 0xFF
949#define ASC_SCSI_BIT_ID_TYPE uchar
950#define ASC_MAX_TID 7
951#define ASC_MAX_LUN 7
952#define ASC_SCSI_WIDTH_BIT_SET 0xFF
953#define ASC_MAX_SENSE_LEN 32
954#define ASC_MIN_SENSE_LEN 14
955#define ASC_MAX_CDB_LEN 12
956#define ASC_SCSI_RESET_HOLD_TIME_US 60
957
958#define ADV_INQ_CLOCKING_ST_ONLY 0x0
959#define ADV_INQ_CLOCKING_DT_ONLY 0x1
960#define ADV_INQ_CLOCKING_ST_AND_DT 0x3
961
962/*
963 * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
964 * and CmdDt (Command Support Data) field bit definitions.
965 */
966#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3
967#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2
968#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1
969#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0
970
971#define ASC_SCSIDIR_NOCHK 0x00
972#define ASC_SCSIDIR_T2H 0x08
973#define ASC_SCSIDIR_H2T 0x10
974#define ASC_SCSIDIR_NODATA 0x18
975#define SCSI_ASC_NOMEDIA 0x3A
976#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
977#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
978#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
979#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8))
980#define MS_CMD_DONE 0x00
981#define MS_EXTEND 0x01
982#define MS_SDTR_LEN 0x03
983#define MS_SDTR_CODE 0x01
984#define MS_WDTR_LEN 0x02
985#define MS_WDTR_CODE 0x03
986#define MS_MDP_LEN 0x05
987#define MS_MDP_CODE 0x00
988
989/*
990 * Inquiry data structure and bitfield macros
991 *
992 * Only quantities of more than 1 bit are shifted, since the others are
993 * just tested for true or false. C bitfields aren't portable between big
994 * and little-endian platforms so they are not used.
995 */
996
997#define ASC_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
998#define ASC_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
999#define ASC_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
1000#define ASC_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
1001#define ASC_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
1002#define ASC_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
1003#define ASC_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
1004#define ASC_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
1005#define ASC_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
1006#define ASC_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
1007#define ASC_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
1008#define ASC_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
1009#define ASC_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
1010#define ASC_INQ_SYNC(inq) ((inq)->flags & 0x10)
1011#define ASC_INQ_WIDE16(inq) ((inq)->flags & 0x20)
1012#define ASC_INQ_WIDE32(inq) ((inq)->flags & 0x40)
1013#define ASC_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
1014#define ASC_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
1015#define ASC_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
1016#define ASC_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
1017
1018typedef struct {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001019 uchar periph;
1020 uchar devtype;
1021 uchar ver;
1022 uchar byte3;
1023 uchar add_len;
1024 uchar res1;
1025 uchar res2;
1026 uchar flags;
1027 uchar vendor_id[8];
1028 uchar product_id[16];
1029 uchar product_rev_level[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030} ASC_SCSI_INQUIRY;
1031
1032#define ASC_SG_LIST_PER_Q 7
1033#define QS_FREE 0x00
1034#define QS_READY 0x01
1035#define QS_DISC1 0x02
1036#define QS_DISC2 0x04
1037#define QS_BUSY 0x08
1038#define QS_ABORTED 0x40
1039#define QS_DONE 0x80
1040#define QC_NO_CALLBACK 0x01
1041#define QC_SG_SWAP_QUEUE 0x02
1042#define QC_SG_HEAD 0x04
1043#define QC_DATA_IN 0x08
1044#define QC_DATA_OUT 0x10
1045#define QC_URGENT 0x20
1046#define QC_MSG_OUT 0x40
1047#define QC_REQ_SENSE 0x80
1048#define QCSG_SG_XFER_LIST 0x02
1049#define QCSG_SG_XFER_MORE 0x04
1050#define QCSG_SG_XFER_END 0x08
1051#define QD_IN_PROGRESS 0x00
1052#define QD_NO_ERROR 0x01
1053#define QD_ABORTED_BY_HOST 0x02
1054#define QD_WITH_ERROR 0x04
1055#define QD_INVALID_REQUEST 0x80
1056#define QD_INVALID_HOST_NUM 0x81
1057#define QD_INVALID_DEVICE 0x82
1058#define QD_ERR_INTERNAL 0xFF
1059#define QHSTA_NO_ERROR 0x00
1060#define QHSTA_M_SEL_TIMEOUT 0x11
1061#define QHSTA_M_DATA_OVER_RUN 0x12
1062#define QHSTA_M_DATA_UNDER_RUN 0x12
1063#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
1064#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
1065#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
1066#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
1067#define QHSTA_D_HOST_ABORT_FAILED 0x23
1068#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
1069#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
1070#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
1071#define QHSTA_M_WTM_TIMEOUT 0x41
1072#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
1073#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
1074#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
1075#define QHSTA_M_TARGET_STATUS_BUSY 0x45
1076#define QHSTA_M_BAD_TAG_CODE 0x46
1077#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
1078#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
1079#define QHSTA_D_LRAM_CMP_ERROR 0x81
1080#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
1081#define ASC_FLAG_SCSIQ_REQ 0x01
1082#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02
1083#define ASC_FLAG_BIOS_ASYNC_IO 0x04
1084#define ASC_FLAG_SRB_LINEAR_ADDR 0x08
1085#define ASC_FLAG_WIN16 0x10
1086#define ASC_FLAG_WIN32 0x20
1087#define ASC_FLAG_ISA_OVER_16MB 0x40
1088#define ASC_FLAG_DOS_VM_CALLBACK 0x80
1089#define ASC_TAG_FLAG_EXTRA_BYTES 0x10
1090#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04
1091#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
1092#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
1093#define ASC_SCSIQ_CPY_BEG 4
1094#define ASC_SCSIQ_SGHD_CPY_BEG 2
1095#define ASC_SCSIQ_B_FWD 0
1096#define ASC_SCSIQ_B_BWD 1
1097#define ASC_SCSIQ_B_STATUS 2
1098#define ASC_SCSIQ_B_QNO 3
1099#define ASC_SCSIQ_B_CNTL 4
1100#define ASC_SCSIQ_B_SG_QUEUE_CNT 5
1101#define ASC_SCSIQ_D_DATA_ADDR 8
1102#define ASC_SCSIQ_D_DATA_CNT 12
1103#define ASC_SCSIQ_B_SENSE_LEN 20
1104#define ASC_SCSIQ_DONE_INFO_BEG 22
1105#define ASC_SCSIQ_D_SRBPTR 22
1106#define ASC_SCSIQ_B_TARGET_IX 26
1107#define ASC_SCSIQ_B_CDB_LEN 28
1108#define ASC_SCSIQ_B_TAG_CODE 29
1109#define ASC_SCSIQ_W_VM_ID 30
1110#define ASC_SCSIQ_DONE_STATUS 32
1111#define ASC_SCSIQ_HOST_STATUS 33
1112#define ASC_SCSIQ_SCSI_STATUS 34
1113#define ASC_SCSIQ_CDB_BEG 36
1114#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
1115#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
1116#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
1117#define ASC_SCSIQ_B_SG_WK_QP 49
1118#define ASC_SCSIQ_B_SG_WK_IX 50
1119#define ASC_SCSIQ_W_ALT_DC1 52
1120#define ASC_SCSIQ_B_LIST_CNT 6
1121#define ASC_SCSIQ_B_CUR_LIST_CNT 7
1122#define ASC_SGQ_B_SG_CNTL 4
1123#define ASC_SGQ_B_SG_HEAD_QP 5
1124#define ASC_SGQ_B_SG_LIST_CNT 6
1125#define ASC_SGQ_B_SG_CUR_LIST_CNT 7
1126#define ASC_SGQ_LIST_BEG 8
1127#define ASC_DEF_SCSI1_QNG 4
1128#define ASC_MAX_SCSI1_QNG 4
1129#define ASC_DEF_SCSI2_QNG 16
1130#define ASC_MAX_SCSI2_QNG 32
1131#define ASC_TAG_CODE_MASK 0x23
1132#define ASC_STOP_REQ_RISC_STOP 0x01
1133#define ASC_STOP_ACK_RISC_STOP 0x03
1134#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10
1135#define ASC_STOP_CLEAN_UP_DISC_Q 0x20
1136#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
1137#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
1138#define ASC_TID_TO_TARGET_ID(tid) (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
1139#define ASC_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ASC_MAX_TID))
1140#define ASC_TIX_TO_TID(tix) ((tix) & ASC_MAX_TID)
1141#define ASC_TID_TO_TIX(tid) ((tid) & ASC_MAX_TID)
1142#define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
1143#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
1144
1145typedef struct asc_scsiq_1 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001146 uchar status;
1147 uchar q_no;
1148 uchar cntl;
1149 uchar sg_queue_cnt;
1150 uchar target_id;
1151 uchar target_lun;
1152 ASC_PADDR data_addr;
1153 ASC_DCNT data_cnt;
1154 ASC_PADDR sense_addr;
1155 uchar sense_len;
1156 uchar extra_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157} ASC_SCSIQ_1;
1158
1159typedef struct asc_scsiq_2 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001160 ASC_VADDR srb_ptr;
1161 uchar target_ix;
1162 uchar flag;
1163 uchar cdb_len;
1164 uchar tag_code;
1165 ushort vm_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166} ASC_SCSIQ_2;
1167
1168typedef struct asc_scsiq_3 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001169 uchar done_stat;
1170 uchar host_stat;
1171 uchar scsi_stat;
1172 uchar scsi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173} ASC_SCSIQ_3;
1174
1175typedef struct asc_scsiq_4 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001176 uchar cdb[ASC_MAX_CDB_LEN];
1177 uchar y_first_sg_list_qp;
1178 uchar y_working_sg_qp;
1179 uchar y_working_sg_ix;
1180 uchar y_res;
1181 ushort x_req_count;
1182 ushort x_reconnect_rtn;
1183 ASC_PADDR x_saved_data_addr;
1184 ASC_DCNT x_saved_data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185} ASC_SCSIQ_4;
1186
1187typedef struct asc_q_done_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001188 ASC_SCSIQ_2 d2;
1189 ASC_SCSIQ_3 d3;
1190 uchar q_status;
1191 uchar q_no;
1192 uchar cntl;
1193 uchar sense_len;
1194 uchar extra_bytes;
1195 uchar res;
1196 ASC_DCNT remain_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197} ASC_QDONE_INFO;
1198
1199typedef struct asc_sg_list {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001200 ASC_PADDR addr;
1201 ASC_DCNT bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202} ASC_SG_LIST;
1203
1204typedef struct asc_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001205 ushort entry_cnt;
1206 ushort queue_cnt;
1207 ushort entry_to_copy;
1208 ushort res;
1209 ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210} ASC_SG_HEAD;
1211
1212#define ASC_MIN_SG_LIST 2
1213
1214typedef struct asc_min_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001215 ushort entry_cnt;
1216 ushort queue_cnt;
1217 ushort entry_to_copy;
1218 ushort res;
1219 ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220} ASC_MIN_SG_HEAD;
1221
1222#define QCX_SORT (0x0001)
1223#define QCX_COALEASE (0x0002)
1224
1225typedef struct asc_scsi_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001226 ASC_SCSIQ_1 q1;
1227 ASC_SCSIQ_2 q2;
1228 uchar *cdbptr;
1229 ASC_SG_HEAD *sg_head;
1230 ushort remain_sg_entry_cnt;
1231 ushort next_sg_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232} ASC_SCSI_Q;
1233
1234typedef struct asc_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001235 ASC_SCSIQ_1 r1;
1236 ASC_SCSIQ_2 r2;
1237 uchar *cdbptr;
1238 ASC_SG_HEAD *sg_head;
1239 uchar *sense_ptr;
1240 ASC_SCSIQ_3 r3;
1241 uchar cdb[ASC_MAX_CDB_LEN];
1242 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243} ASC_SCSI_REQ_Q;
1244
1245typedef struct asc_scsi_bios_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001246 ASC_SCSIQ_1 r1;
1247 ASC_SCSIQ_2 r2;
1248 uchar *cdbptr;
1249 ASC_SG_HEAD *sg_head;
1250 uchar *sense_ptr;
1251 ASC_SCSIQ_3 r3;
1252 uchar cdb[ASC_MAX_CDB_LEN];
1253 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254} ASC_SCSI_BIOS_REQ_Q;
1255
1256typedef struct asc_risc_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001257 uchar fwd;
1258 uchar bwd;
1259 ASC_SCSIQ_1 i1;
1260 ASC_SCSIQ_2 i2;
1261 ASC_SCSIQ_3 i3;
1262 ASC_SCSIQ_4 i4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263} ASC_RISC_Q;
1264
1265typedef struct asc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001266 uchar seq_no;
1267 uchar q_no;
1268 uchar cntl;
1269 uchar sg_head_qp;
1270 uchar sg_list_cnt;
1271 uchar sg_cur_list_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272} ASC_SG_LIST_Q;
1273
1274typedef struct asc_risc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001275 uchar fwd;
1276 uchar bwd;
1277 ASC_SG_LIST_Q sg;
1278 ASC_SG_LIST sg_list[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279} ASC_RISC_SG_LIST_Q;
1280
1281#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
1282#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024
1283#define ASCQ_ERR_NO_ERROR 0
1284#define ASCQ_ERR_IO_NOT_FOUND 1
1285#define ASCQ_ERR_LOCAL_MEM 2
1286#define ASCQ_ERR_CHKSUM 3
1287#define ASCQ_ERR_START_CHIP 4
1288#define ASCQ_ERR_INT_TARGET_ID 5
1289#define ASCQ_ERR_INT_LOCAL_MEM 6
1290#define ASCQ_ERR_HALT_RISC 7
1291#define ASCQ_ERR_GET_ASPI_ENTRY 8
1292#define ASCQ_ERR_CLOSE_ASPI 9
1293#define ASCQ_ERR_HOST_INQUIRY 0x0A
1294#define ASCQ_ERR_SAVED_SRB_BAD 0x0B
1295#define ASCQ_ERR_QCNTL_SG_LIST 0x0C
1296#define ASCQ_ERR_Q_STATUS 0x0D
1297#define ASCQ_ERR_WR_SCSIQ 0x0E
1298#define ASCQ_ERR_PC_ADDR 0x0F
1299#define ASCQ_ERR_SYN_OFFSET 0x10
1300#define ASCQ_ERR_SYN_XFER_TIME 0x11
1301#define ASCQ_ERR_LOCK_DMA 0x12
1302#define ASCQ_ERR_UNLOCK_DMA 0x13
1303#define ASCQ_ERR_VDS_CHK_INSTALL 0x14
1304#define ASCQ_ERR_MICRO_CODE_HALT 0x15
1305#define ASCQ_ERR_SET_LRAM_ADDR 0x16
1306#define ASCQ_ERR_CUR_QNG 0x17
1307#define ASCQ_ERR_SG_Q_LINKS 0x18
1308#define ASCQ_ERR_SCSIQ_PTR 0x19
1309#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
1310#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
1311#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
1312#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D
1313#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
1314#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F
1315#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20
1316#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21
1317#define ASCQ_ERR_SEND_SCSI_Q 0x22
1318#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23
1319#define ASCQ_ERR_RESET_SDTR 0x24
1320
1321/*
1322 * Warning code values are set in ASC_DVC_VAR 'warn_code'.
1323 */
1324#define ASC_WARN_NO_ERROR 0x0000
1325#define ASC_WARN_IO_PORT_ROTATE 0x0001
1326#define ASC_WARN_EEPROM_CHKSUM 0x0002
1327#define ASC_WARN_IRQ_MODIFIED 0x0004
1328#define ASC_WARN_AUTO_CONFIG 0x0008
1329#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
1330#define ASC_WARN_EEPROM_RECOVER 0x0020
1331#define ASC_WARN_CFG_MSW_RECOVER 0x0040
1332#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
1333
1334/*
1335 * Error code values are set in ASC_DVC_VAR 'err_code'.
1336 */
1337#define ASC_IERR_WRITE_EEPROM 0x0001
1338#define ASC_IERR_MCODE_CHKSUM 0x0002
1339#define ASC_IERR_SET_PC_ADDR 0x0004
1340#define ASC_IERR_START_STOP_CHIP 0x0008
1341#define ASC_IERR_IRQ_NO 0x0010
1342#define ASC_IERR_SET_IRQ_NO 0x0020
1343#define ASC_IERR_CHIP_VERSION 0x0040
1344#define ASC_IERR_SET_SCSI_ID 0x0080
1345#define ASC_IERR_GET_PHY_ADDR 0x0100
1346#define ASC_IERR_BAD_SIGNATURE 0x0200
1347#define ASC_IERR_NO_BUS_TYPE 0x0400
1348#define ASC_IERR_SCAM 0x0800
1349#define ASC_IERR_SET_SDTR 0x1000
1350#define ASC_IERR_RW_LRAM 0x8000
1351
1352#define ASC_DEF_IRQ_NO 10
1353#define ASC_MAX_IRQ_NO 15
1354#define ASC_MIN_IRQ_NO 10
1355#define ASC_MIN_REMAIN_Q (0x02)
1356#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
1357#define ASC_MIN_TAG_Q_PER_DVC (0x04)
1358#define ASC_DEF_TAG_Q_PER_DVC (0x04)
1359#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q
1360#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
1361#define ASC_MAX_TOTAL_QNG 240
1362#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
1363#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
1364#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
1365#define ASC_MAX_INRAM_TAG_QNG 16
1366#define ASC_IOADR_TABLE_MAX_IX 11
1367#define ASC_IOADR_GAP 0x10
1368#define ASC_SEARCH_IOP_GAP 0x10
1369#define ASC_MIN_IOP_ADDR (PortAddr)0x0100
1370#define ASC_MAX_IOP_ADDR (PortAddr)0x3F0
1371#define ASC_IOADR_1 (PortAddr)0x0110
1372#define ASC_IOADR_2 (PortAddr)0x0130
1373#define ASC_IOADR_3 (PortAddr)0x0150
1374#define ASC_IOADR_4 (PortAddr)0x0190
1375#define ASC_IOADR_5 (PortAddr)0x0210
1376#define ASC_IOADR_6 (PortAddr)0x0230
1377#define ASC_IOADR_7 (PortAddr)0x0250
1378#define ASC_IOADR_8 (PortAddr)0x0330
1379#define ASC_IOADR_DEF ASC_IOADR_8
1380#define ASC_LIB_SCSIQ_WK_SP 256
1381#define ASC_MAX_SYN_XFER_NO 16
1382#define ASC_SYN_MAX_OFFSET 0x0F
1383#define ASC_DEF_SDTR_OFFSET 0x0F
1384#define ASC_DEF_SDTR_INDEX 0x00
1385#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
1386#define SYN_XFER_NS_0 25
1387#define SYN_XFER_NS_1 30
1388#define SYN_XFER_NS_2 35
1389#define SYN_XFER_NS_3 40
1390#define SYN_XFER_NS_4 50
1391#define SYN_XFER_NS_5 60
1392#define SYN_XFER_NS_6 70
1393#define SYN_XFER_NS_7 85
1394#define SYN_ULTRA_XFER_NS_0 12
1395#define SYN_ULTRA_XFER_NS_1 19
1396#define SYN_ULTRA_XFER_NS_2 25
1397#define SYN_ULTRA_XFER_NS_3 32
1398#define SYN_ULTRA_XFER_NS_4 38
1399#define SYN_ULTRA_XFER_NS_5 44
1400#define SYN_ULTRA_XFER_NS_6 50
1401#define SYN_ULTRA_XFER_NS_7 57
1402#define SYN_ULTRA_XFER_NS_8 63
1403#define SYN_ULTRA_XFER_NS_9 69
1404#define SYN_ULTRA_XFER_NS_10 75
1405#define SYN_ULTRA_XFER_NS_11 82
1406#define SYN_ULTRA_XFER_NS_12 88
1407#define SYN_ULTRA_XFER_NS_13 94
1408#define SYN_ULTRA_XFER_NS_14 100
1409#define SYN_ULTRA_XFER_NS_15 107
1410
1411typedef struct ext_msg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001412 uchar msg_type;
1413 uchar msg_len;
1414 uchar msg_req;
1415 union {
1416 struct {
1417 uchar sdtr_xfer_period;
1418 uchar sdtr_req_ack_offset;
1419 } sdtr;
1420 struct {
1421 uchar wdtr_width;
1422 } wdtr;
1423 struct {
1424 uchar mdp_b3;
1425 uchar mdp_b2;
1426 uchar mdp_b1;
1427 uchar mdp_b0;
1428 } mdp;
1429 } u_ext_msg;
1430 uchar res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431} EXT_MSG;
1432
1433#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
1434#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
1435#define wdtr_width u_ext_msg.wdtr.wdtr_width
1436#define mdp_b3 u_ext_msg.mdp_b3
1437#define mdp_b2 u_ext_msg.mdp_b2
1438#define mdp_b1 u_ext_msg.mdp_b1
1439#define mdp_b0 u_ext_msg.mdp_b0
1440
1441typedef struct asc_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001442 ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
1443 ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
1444 ASC_SCSI_BIT_ID_TYPE disc_enable;
1445 ASC_SCSI_BIT_ID_TYPE sdtr_enable;
1446 uchar chip_scsi_id;
1447 uchar isa_dma_speed;
1448 uchar isa_dma_channel;
1449 uchar chip_version;
1450 ushort lib_serial_no;
1451 ushort lib_version;
1452 ushort mcode_date;
1453 ushort mcode_version;
1454 uchar max_tag_qng[ASC_MAX_TID + 1];
1455 uchar *overrun_buf;
1456 uchar sdtr_period_offset[ASC_MAX_TID + 1];
1457 ushort pci_slot_info;
1458 uchar adapter_info[6];
1459 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460} ASC_DVC_CFG;
1461
1462#define ASC_DEF_DVC_CNTL 0xFFFF
1463#define ASC_DEF_CHIP_SCSI_ID 7
1464#define ASC_DEF_ISA_DMA_SPEED 4
1465#define ASC_INIT_STATE_NULL 0x0000
1466#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
1467#define ASC_INIT_STATE_END_GET_CFG 0x0002
1468#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
1469#define ASC_INIT_STATE_END_SET_CFG 0x0008
1470#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
1471#define ASC_INIT_STATE_END_LOAD_MC 0x0020
1472#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
1473#define ASC_INIT_STATE_END_INQUIRY 0x0080
1474#define ASC_INIT_RESET_SCSI_DONE 0x0100
1475#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
1477#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
1478#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
1479#define ASC_MIN_TAGGED_CMD 7
1480#define ASC_MAX_SCSI_RESET_WAIT 30
1481
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001482struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001484typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
1485typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
1487typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001488 PortAddr iop_base;
1489 ushort err_code;
1490 ushort dvc_cntl;
1491 ushort bug_fix_cntl;
1492 ushort bus_type;
1493 ASC_ISR_CALLBACK isr_callback;
1494 ASC_EXE_CALLBACK exe_callback;
1495 ASC_SCSI_BIT_ID_TYPE init_sdtr;
1496 ASC_SCSI_BIT_ID_TYPE sdtr_done;
1497 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
1498 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
1499 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
1500 ASC_SCSI_BIT_ID_TYPE start_motor;
1501 uchar scsi_reset_wait;
1502 uchar chip_no;
1503 char is_in_int;
1504 uchar max_total_qng;
1505 uchar cur_total_qng;
1506 uchar in_critical_cnt;
1507 uchar irq_no;
1508 uchar last_q_shortage;
1509 ushort init_state;
1510 uchar cur_dvc_qng[ASC_MAX_TID + 1];
1511 uchar max_dvc_qng[ASC_MAX_TID + 1];
1512 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
1513 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
1514 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
1515 ASC_DVC_CFG *cfg;
1516 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
1517 char redo_scam;
1518 ushort res2;
1519 uchar dos_int13_table[ASC_MAX_TID + 1];
1520 ASC_DCNT max_dma_count;
1521 ASC_SCSI_BIT_ID_TYPE no_scam;
1522 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
1523 uchar max_sdtr_index;
1524 uchar host_init_sdtr_index;
1525 struct asc_board *drv_ptr;
1526 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527} ASC_DVC_VAR;
1528
1529typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001530 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531} ASC_DVC_INQ_INFO;
1532
1533typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001534 ASC_DCNT lba;
1535 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536} ASC_CAP_INFO;
1537
1538typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001539 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540} ASC_CAP_INFO_ARRAY;
1541
1542#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
1543#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
1544#define ASC_CNTL_INITIATOR (ushort)0x0001
1545#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
1546#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
1547#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
1548#define ASC_CNTL_NO_SCAM (ushort)0x0010
1549#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
1550#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
1551#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
1552#define ASC_CNTL_RESET_SCSI (ushort)0x0200
1553#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
1554#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
1555#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
1556#define ASC_CNTL_BURST_MODE (ushort)0x2000
1557#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
1558#define ASC_EEP_DVC_CFG_BEG_VL 2
1559#define ASC_EEP_MAX_DVC_ADDR_VL 15
1560#define ASC_EEP_DVC_CFG_BEG 32
1561#define ASC_EEP_MAX_DVC_ADDR 45
1562#define ASC_EEP_DEFINED_WORDS 10
1563#define ASC_EEP_MAX_ADDR 63
1564#define ASC_EEP_RES_WORDS 0
1565#define ASC_EEP_MAX_RETRY 20
1566#define ASC_MAX_INIT_BUSY_RETRY 8
1567#define ASC_EEP_ISA_PNP_WSIZE 16
1568
1569/*
1570 * These macros keep the chip SCSI id and ISA DMA speed
1571 * bitfields in board order. C bitfields aren't portable
1572 * between big and little-endian platforms so they are
1573 * not used.
1574 */
1575
1576#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
1577#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
1578#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
1579 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
1580#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
1581 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
1582
1583typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001584 ushort cfg_lsw;
1585 ushort cfg_msw;
1586 uchar init_sdtr;
1587 uchar disc_enable;
1588 uchar use_cmd_qng;
1589 uchar start_motor;
1590 uchar max_total_qng;
1591 uchar max_tag_qng;
1592 uchar bios_scan;
1593 uchar power_up_wait;
1594 uchar no_scam;
1595 uchar id_speed; /* low order 4 bits is chip scsi id */
1596 /* high order 4 bits is isa dma speed */
1597 uchar dos_int13_table[ASC_MAX_TID + 1];
1598 uchar adapter_info[6];
1599 ushort cntl;
1600 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601} ASCEEP_CONFIG;
1602
1603#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
1604#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
1605#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
1606
1607#define ASC_EEP_CMD_READ 0x80
1608#define ASC_EEP_CMD_WRITE 0x40
1609#define ASC_EEP_CMD_WRITE_ABLE 0x30
1610#define ASC_EEP_CMD_WRITE_DISABLE 0x00
1611#define ASC_OVERRUN_BSIZE 0x00000048UL
1612#define ASC_CTRL_BREAK_ONCE 0x0001
1613#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
1614#define ASCV_MSGOUT_BEG 0x0000
1615#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
1616#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
1617#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
1618#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
1619#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
1620#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
1621#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
1622#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
1623#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
1624#define ASCV_BREAK_ADDR (ushort)0x0028
1625#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
1626#define ASCV_BREAK_CONTROL (ushort)0x002C
1627#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
1628
1629#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
1630#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
1631#define ASCV_MCODE_SIZE_W (ushort)0x0034
1632#define ASCV_STOP_CODE_B (ushort)0x0036
1633#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
1634#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
1635#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
1636#define ASCV_HALTCODE_W (ushort)0x0040
1637#define ASCV_CHKSUM_W (ushort)0x0042
1638#define ASCV_MC_DATE_W (ushort)0x0044
1639#define ASCV_MC_VER_W (ushort)0x0046
1640#define ASCV_NEXTRDY_B (ushort)0x0048
1641#define ASCV_DONENEXT_B (ushort)0x0049
1642#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
1643#define ASCV_SCSIBUSY_B (ushort)0x004B
1644#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
1645#define ASCV_CURCDB_B (ushort)0x004D
1646#define ASCV_RCLUN_B (ushort)0x004E
1647#define ASCV_BUSY_QHEAD_B (ushort)0x004F
1648#define ASCV_DISC1_QHEAD_B (ushort)0x0050
1649#define ASCV_DISC_ENABLE_B (ushort)0x0052
1650#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
1651#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
1652#define ASCV_MCODE_CNTL_B (ushort)0x0056
1653#define ASCV_NULL_TARGET_B (ushort)0x0057
1654#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
1655#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
1656#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
1657#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
1658#define ASCV_HOST_FLAG_B (ushort)0x005D
1659#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
1660#define ASCV_VER_SERIAL_B (ushort)0x0065
1661#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
1662#define ASCV_WTM_FLAG_B (ushort)0x0068
1663#define ASCV_RISC_FLAG_B (ushort)0x006A
1664#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
1665#define ASC_HOST_FLAG_IN_ISR 0x01
1666#define ASC_HOST_FLAG_ACK_INT 0x02
1667#define ASC_RISC_FLAG_GEN_INT 0x01
1668#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
1669#define IOP_CTRL (0x0F)
1670#define IOP_STATUS (0x0E)
1671#define IOP_INT_ACK IOP_STATUS
1672#define IOP_REG_IFC (0x0D)
1673#define IOP_SYN_OFFSET (0x0B)
1674#define IOP_EXTRA_CONTROL (0x0D)
1675#define IOP_REG_PC (0x0C)
1676#define IOP_RAM_ADDR (0x0A)
1677#define IOP_RAM_DATA (0x08)
1678#define IOP_EEP_DATA (0x06)
1679#define IOP_EEP_CMD (0x07)
1680#define IOP_VERSION (0x03)
1681#define IOP_CONFIG_HIGH (0x04)
1682#define IOP_CONFIG_LOW (0x02)
1683#define IOP_SIG_BYTE (0x01)
1684#define IOP_SIG_WORD (0x00)
1685#define IOP_REG_DC1 (0x0E)
1686#define IOP_REG_DC0 (0x0C)
1687#define IOP_REG_SB (0x0B)
1688#define IOP_REG_DA1 (0x0A)
1689#define IOP_REG_DA0 (0x08)
1690#define IOP_REG_SC (0x09)
1691#define IOP_DMA_SPEED (0x07)
1692#define IOP_REG_FLAG (0x07)
1693#define IOP_FIFO_H (0x06)
1694#define IOP_FIFO_L (0x04)
1695#define IOP_REG_ID (0x05)
1696#define IOP_REG_QP (0x03)
1697#define IOP_REG_IH (0x02)
1698#define IOP_REG_IX (0x01)
1699#define IOP_REG_AX (0x00)
1700#define IFC_REG_LOCK (0x00)
1701#define IFC_REG_UNLOCK (0x09)
1702#define IFC_WR_EN_FILTER (0x10)
1703#define IFC_RD_NO_EEPROM (0x10)
1704#define IFC_SLEW_RATE (0x20)
1705#define IFC_ACT_NEG (0x40)
1706#define IFC_INP_FILTER (0x80)
1707#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
1708#define SC_SEL (uchar)(0x80)
1709#define SC_BSY (uchar)(0x40)
1710#define SC_ACK (uchar)(0x20)
1711#define SC_REQ (uchar)(0x10)
1712#define SC_ATN (uchar)(0x08)
1713#define SC_IO (uchar)(0x04)
1714#define SC_CD (uchar)(0x02)
1715#define SC_MSG (uchar)(0x01)
1716#define SEC_SCSI_CTL (uchar)(0x80)
1717#define SEC_ACTIVE_NEGATE (uchar)(0x40)
1718#define SEC_SLEW_RATE (uchar)(0x20)
1719#define SEC_ENABLE_FILTER (uchar)(0x10)
1720#define ASC_HALT_EXTMSG_IN (ushort)0x8000
1721#define ASC_HALT_CHK_CONDITION (ushort)0x8100
1722#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
1723#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
1724#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
1725#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
1726#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
1727#define ASC_MAX_QNO 0xF8
1728#define ASC_DATA_SEC_BEG (ushort)0x0080
1729#define ASC_DATA_SEC_END (ushort)0x0080
1730#define ASC_CODE_SEC_BEG (ushort)0x0080
1731#define ASC_CODE_SEC_END (ushort)0x0080
1732#define ASC_QADR_BEG (0x4000)
1733#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
1734#define ASC_QADR_END (ushort)0x7FFF
1735#define ASC_QLAST_ADR (ushort)0x7FC0
1736#define ASC_QBLK_SIZE 0x40
1737#define ASC_BIOS_DATA_QBEG 0xF8
1738#define ASC_MIN_ACTIVE_QNO 0x01
1739#define ASC_QLINK_END 0xFF
1740#define ASC_EEPROM_WORDS 0x10
1741#define ASC_MAX_MGS_LEN 0x10
1742#define ASC_BIOS_ADDR_DEF 0xDC00
1743#define ASC_BIOS_SIZE 0x3800
1744#define ASC_BIOS_RAM_OFF 0x3800
1745#define ASC_BIOS_RAM_SIZE 0x800
1746#define ASC_BIOS_MIN_ADDR 0xC000
1747#define ASC_BIOS_MAX_ADDR 0xEC00
1748#define ASC_BIOS_BANK_SIZE 0x0400
1749#define ASC_MCODE_START_ADDR 0x0080
1750#define ASC_CFG0_HOST_INT_ON 0x0020
1751#define ASC_CFG0_BIOS_ON 0x0040
1752#define ASC_CFG0_VERA_BURST_ON 0x0080
1753#define ASC_CFG0_SCSI_PARITY_ON 0x0800
1754#define ASC_CFG1_SCSI_TARGET_ON 0x0080
1755#define ASC_CFG1_LRAM_8BITS_ON 0x0800
1756#define ASC_CFG_MSW_CLR_MASK 0x3080
1757#define CSW_TEST1 (ASC_CS_TYPE)0x8000
1758#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
1759#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
1760#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
1761#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
1762#define CSW_TEST2 (ASC_CS_TYPE)0x0400
1763#define CSW_TEST3 (ASC_CS_TYPE)0x0200
1764#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
1765#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
1766#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
1767#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
1768#define CSW_HALTED (ASC_CS_TYPE)0x0010
1769#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
1770#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
1771#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
1772#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
1773#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
1774#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
1775#define CIW_TEST1 (ASC_CS_TYPE)0x0200
1776#define CIW_TEST2 (ASC_CS_TYPE)0x0400
1777#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
1778#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
1779#define CC_CHIP_RESET (uchar)0x80
1780#define CC_SCSI_RESET (uchar)0x40
1781#define CC_HALT (uchar)0x20
1782#define CC_SINGLE_STEP (uchar)0x10
1783#define CC_DMA_ABLE (uchar)0x08
1784#define CC_TEST (uchar)0x04
1785#define CC_BANK_ONE (uchar)0x02
1786#define CC_DIAG (uchar)0x01
1787#define ASC_1000_ID0W 0x04C1
1788#define ASC_1000_ID0W_FIX 0x00C1
1789#define ASC_1000_ID1B 0x25
1790#define ASC_EISA_BIG_IOP_GAP (0x1C30-0x0C50)
1791#define ASC_EISA_SMALL_IOP_GAP (0x0020)
1792#define ASC_EISA_MIN_IOP_ADDR (0x0C30)
1793#define ASC_EISA_MAX_IOP_ADDR (0xFC50)
1794#define ASC_EISA_REV_IOP_MASK (0x0C83)
1795#define ASC_EISA_PID_IOP_MASK (0x0C80)
1796#define ASC_EISA_CFG_IOP_MASK (0x0C86)
1797#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
1798#define ASC_EISA_ID_740 0x01745004UL
1799#define ASC_EISA_ID_750 0x01755004UL
1800#define INS_HALTINT (ushort)0x6281
1801#define INS_HALT (ushort)0x6280
1802#define INS_SINT (ushort)0x6200
1803#define INS_RFLAG_WTM (ushort)0x7380
1804#define ASC_MC_SAVE_CODE_WSIZE 0x500
1805#define ASC_MC_SAVE_DATA_WSIZE 0x40
1806
1807typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001808 ushort data[ASC_MC_SAVE_DATA_WSIZE];
1809 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810} ASC_MC_SAVED;
1811
1812#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
1813#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
1814#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
1815#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
1816#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
1817#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
1818#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
1819#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
1820#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
1821#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
1822#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
1823#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
1824#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
1825#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
1826#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
1827#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
1828#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
1829#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
1830#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
1831#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
1832#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
1833#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
1834#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
1835#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
1836#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
1837#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
1838#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
1839#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
1840#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
1841#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
1842#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
1843#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
1844#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
1845#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
1846#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
1847#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
1848#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
1849#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
1850#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
1851#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
1852#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
1853#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
1854#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
1855#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
1856#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
1857#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
1858#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
1859#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
1860#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
1861#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
1862#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
1863#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
1864#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
1865#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
1866#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
1867#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
1868#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
1869#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
1870#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
1871#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
1872#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
1873#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
1874#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
1875#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
1876#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
1877#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
1878#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
1879#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
1880
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001881static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
1882static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
1883static void AscWaitEEPRead(void);
1884static void AscWaitEEPWrite(void);
1885static ushort AscReadEEPWord(PortAddr, uchar);
1886static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
1887static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1888static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
1889static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1890static int AscStartChip(PortAddr);
1891static int AscStopChip(PortAddr);
1892static void AscSetChipIH(PortAddr, ushort);
1893static int AscIsChipHalted(PortAddr);
1894static void AscAckInterrupt(PortAddr);
1895static void AscDisableInterrupt(PortAddr);
1896static void AscEnableInterrupt(PortAddr);
1897static void AscSetBank(PortAddr, uchar);
1898static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001900static ushort AscGetIsaDmaChannel(PortAddr);
1901static ushort AscSetIsaDmaChannel(PortAddr, ushort);
1902static uchar AscSetIsaDmaSpeed(PortAddr, uchar);
1903static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001905static uchar AscReadLramByte(PortAddr, ushort);
1906static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001908static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001910static void AscWriteLramWord(PortAddr, ushort, ushort);
1911static void AscWriteLramByte(PortAddr, ushort, uchar);
1912static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
1913static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
1914static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1915static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1916static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
1917static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
1918static ushort AscInitFromEEP(ASC_DVC_VAR *);
1919static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
1920static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1921static int AscTestExternalLram(ASC_DVC_VAR *);
1922static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1923static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1924static void AscSetChipSDTR(PortAddr, uchar, uchar);
1925static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1926static uchar AscAllocFreeQueue(PortAddr, uchar);
1927static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1928static int AscHostReqRiscHalt(PortAddr);
1929static int AscStopQueueExe(PortAddr);
1930static int AscSendScsiQueue(ASC_DVC_VAR *,
1931 ASC_SCSI_Q *scsiq, uchar n_q_required);
1932static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1933static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1934static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1935static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1936static ushort AscInitLram(ASC_DVC_VAR *);
1937static ushort AscInitQLinkVar(ASC_DVC_VAR *);
1938static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1939static int AscIsrChipHalted(ASC_DVC_VAR *);
1940static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1941 ASC_QDONE_INFO *, ASC_DCNT);
1942static int AscIsrQDone(ASC_DVC_VAR *);
1943static int AscCompareString(uchar *, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001945static ushort AscGetEisaChipCfg(PortAddr);
1946static ASC_DCNT AscGetEisaProductID(PortAddr);
1947static PortAddr AscSearchIOPortAddrEISA(PortAddr);
1948static PortAddr AscSearchIOPortAddr11(PortAddr);
1949static PortAddr AscSearchIOPortAddr(PortAddr, ushort);
1950static void AscSetISAPNPWaitForKey(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001952static uchar AscGetChipScsiCtrl(PortAddr);
1953static uchar AscSetChipScsiID(PortAddr, uchar);
1954static uchar AscGetChipVersion(PortAddr, ushort);
1955static ushort AscGetChipBusType(PortAddr);
1956static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
1957static int AscFindSignature(PortAddr);
1958static void AscToggleIRQAct(PortAddr);
1959static uchar AscGetChipIRQ(PortAddr, ushort);
1960static uchar AscSetChipIRQ(PortAddr, uchar, ushort);
1961static ushort AscGetChipBiosAddress(PortAddr, ushort);
1962static inline ulong DvcEnterCritical(void);
1963static inline void DvcLeaveCritical(ulong);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001965static uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
1966static void DvcWritePCIConfigByte(ASC_DVC_VAR *, ushort, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001968static ushort AscGetChipBiosAddress(PortAddr, ushort);
1969static void DvcSleepMilliSecond(ASC_DCNT);
1970static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
1971static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1972static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
1973static ushort AscInitGetConfig(ASC_DVC_VAR *);
1974static ushort AscInitSetConfig(ASC_DVC_VAR *);
1975static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
1976static void AscAsyncFix(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
1977static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
1978static void AscInquiryHandling(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
1979static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1980static int AscISR(ASC_DVC_VAR *);
1981static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1982static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001984static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001986static ASC_DCNT AscGetMaxDmaCount(ushort);
1987static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988
1989/*
1990 * --- Adv Library Constants and Macros
1991 */
1992
1993#define ADV_LIB_VERSION_MAJOR 5
1994#define ADV_LIB_VERSION_MINOR 14
1995
1996/*
1997 * Define Adv Library required special types.
1998 */
1999
2000/*
2001 * Portable Data Types
2002 *
2003 * Any instance where a 32-bit long or pointer type is assumed
2004 * for precision or HW defined structures, the following define
2005 * types must be used. In Linux the char, short, and int types
2006 * are all consistent at 8, 16, and 32 bits respectively. Pointers
2007 * and long types are 64 bits on Alpha and UltraSPARC.
2008 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002009#define ADV_PADDR __u32 /* Physical address data type. */
2010#define ADV_VADDR __u32 /* Virtual address data type. */
2011#define ADV_DCNT __u32 /* Unsigned Data count type. */
2012#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
2014/*
2015 * These macros are used to convert a virtual address to a
2016 * 32-bit value. This currently can be used on Linux Alpha
2017 * which uses 64-bit virtual address but a 32-bit bus address.
2018 * This is likely to break in the future, but doing this now
2019 * will give us time to change the HW and FW to handle 64-bit
2020 * addresses.
2021 */
2022#define ADV_VADDR_TO_U32 virt_to_bus
2023#define ADV_U32_TO_VADDR bus_to_virt
2024
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002025#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
2027/*
2028 * Define Adv Library required memory access macros.
2029 */
2030#define ADV_MEM_READB(addr) readb(addr)
2031#define ADV_MEM_READW(addr) readw(addr)
2032#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
2033#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
2034#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
2035
2036#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
2037
2038/*
2039 * For wide boards a CDB length maximum of 16 bytes
2040 * is supported.
2041 */
2042#define ADV_MAX_CDB_LEN 16
2043
2044/*
2045 * Define total number of simultaneous maximum element scatter-gather
2046 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
2047 * maximum number of outstanding commands per wide host adapter. Each
2048 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
2049 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
2050 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
2051 * structures or 255 scatter-gather elements.
2052 *
2053 */
2054#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
2055
2056/*
2057 * Define Adv Library required maximum number of scatter-gather
2058 * elements per request.
2059 */
2060#define ADV_MAX_SG_LIST 255
2061
2062/* Number of SG blocks needed. */
2063#define ADV_NUM_SG_BLOCK \
2064 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
2065
2066/* Total contiguous memory needed for SG blocks. */
2067#define ADV_SG_TOTAL_MEM_SIZE \
2068 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
2069
2070#define ADV_PAGE_SIZE PAGE_SIZE
2071
2072#define ADV_NUM_PAGE_CROSSING \
2073 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2074
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075#define ADV_EEP_DVC_CFG_BEGIN (0x00)
2076#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002077#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078#define ADV_EEP_MAX_WORD_ADDR (0x1E)
2079
2080#define ADV_EEP_DELAY_MS 100
2081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002082#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
2083#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084/*
2085 * For the ASC3550 Bit 13 is Termination Polarity control bit.
2086 * For later ICs Bit 13 controls whether the CIS (Card Information
2087 * Service Section) is loaded from EEPROM.
2088 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002089#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
2090#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091/*
2092 * ASC38C1600 Bit 11
2093 *
2094 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
2095 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
2096 * Function 0 will specify INT B.
2097 *
2098 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
2099 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
2100 * Function 1 will specify INT A.
2101 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002102#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002104typedef struct adveep_3550_config {
2105 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002107 ushort cfg_lsw; /* 00 power up initialization */
2108 /* bit 13 set - Term Polarity Control */
2109 /* bit 14 set - BIOS Enable */
2110 /* bit 15 set - Big Endian Mode */
2111 ushort cfg_msw; /* 01 unused */
2112 ushort disc_enable; /* 02 disconnect enable */
2113 ushort wdtr_able; /* 03 Wide DTR able */
2114 ushort sdtr_able; /* 04 Synchronous DTR able */
2115 ushort start_motor; /* 05 send start up motor */
2116 ushort tagqng_able; /* 06 tag queuing able */
2117 ushort bios_scan; /* 07 BIOS device control */
2118 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002120 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2121 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002123 uchar scsi_reset_delay; /* 10 reset delay */
2124 uchar bios_id_lun; /* first boot device scsi id & lun */
2125 /* high nibble is lun */
2126 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002128 uchar termination; /* 11 0 - automatic */
2129 /* 1 - low off / high off */
2130 /* 2 - low off / high on */
2131 /* 3 - low on / high on */
2132 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002134 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002136 ushort bios_ctrl; /* 12 BIOS control bits */
2137 /* bit 0 BIOS don't act as initiator. */
2138 /* bit 1 BIOS > 1 GB support */
2139 /* bit 2 BIOS > 2 Disk Support */
2140 /* bit 3 BIOS don't support removables */
2141 /* bit 4 BIOS support bootable CD */
2142 /* bit 5 BIOS scan enabled */
2143 /* bit 6 BIOS support multiple LUNs */
2144 /* bit 7 BIOS display of message */
2145 /* bit 8 SCAM disabled */
2146 /* bit 9 Reset SCSI bus during init. */
2147 /* bit 10 */
2148 /* bit 11 No verbose initialization. */
2149 /* bit 12 SCSI parity enabled */
2150 /* bit 13 */
2151 /* bit 14 */
2152 /* bit 15 */
2153 ushort ultra_able; /* 13 ULTRA speed able */
2154 ushort reserved2; /* 14 reserved */
2155 uchar max_host_qng; /* 15 maximum host queuing */
2156 uchar max_dvc_qng; /* maximum per device queuing */
2157 ushort dvc_cntl; /* 16 control bit for driver */
2158 ushort bug_fix; /* 17 control bit for bug fix */
2159 ushort serial_number_word1; /* 18 Board serial number word 1 */
2160 ushort serial_number_word2; /* 19 Board serial number word 2 */
2161 ushort serial_number_word3; /* 20 Board serial number word 3 */
2162 ushort check_sum; /* 21 EEP check sum */
2163 uchar oem_name[16]; /* 22 OEM name */
2164 ushort dvc_err_code; /* 30 last device driver error code */
2165 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2166 ushort adv_err_addr; /* 32 last uc error address */
2167 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2168 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2169 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2170 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171} ADVEEP_3550_CONFIG;
2172
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002173typedef struct adveep_38C0800_config {
2174 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002176 ushort cfg_lsw; /* 00 power up initialization */
2177 /* bit 13 set - Load CIS */
2178 /* bit 14 set - BIOS Enable */
2179 /* bit 15 set - Big Endian Mode */
2180 ushort cfg_msw; /* 01 unused */
2181 ushort disc_enable; /* 02 disconnect enable */
2182 ushort wdtr_able; /* 03 Wide DTR able */
2183 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2184 ushort start_motor; /* 05 send start up motor */
2185 ushort tagqng_able; /* 06 tag queuing able */
2186 ushort bios_scan; /* 07 BIOS device control */
2187 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002189 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2190 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002192 uchar scsi_reset_delay; /* 10 reset delay */
2193 uchar bios_id_lun; /* first boot device scsi id & lun */
2194 /* high nibble is lun */
2195 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002197 uchar termination_se; /* 11 0 - automatic */
2198 /* 1 - low off / high off */
2199 /* 2 - low off / high on */
2200 /* 3 - low on / high on */
2201 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002203 uchar termination_lvd; /* 11 0 - automatic */
2204 /* 1 - low off / high off */
2205 /* 2 - low off / high on */
2206 /* 3 - low on / high on */
2207 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002209 ushort bios_ctrl; /* 12 BIOS control bits */
2210 /* bit 0 BIOS don't act as initiator. */
2211 /* bit 1 BIOS > 1 GB support */
2212 /* bit 2 BIOS > 2 Disk Support */
2213 /* bit 3 BIOS don't support removables */
2214 /* bit 4 BIOS support bootable CD */
2215 /* bit 5 BIOS scan enabled */
2216 /* bit 6 BIOS support multiple LUNs */
2217 /* bit 7 BIOS display of message */
2218 /* bit 8 SCAM disabled */
2219 /* bit 9 Reset SCSI bus during init. */
2220 /* bit 10 */
2221 /* bit 11 No verbose initialization. */
2222 /* bit 12 SCSI parity enabled */
2223 /* bit 13 */
2224 /* bit 14 */
2225 /* bit 15 */
2226 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2227 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2228 uchar max_host_qng; /* 15 maximum host queueing */
2229 uchar max_dvc_qng; /* maximum per device queuing */
2230 ushort dvc_cntl; /* 16 control bit for driver */
2231 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2232 ushort serial_number_word1; /* 18 Board serial number word 1 */
2233 ushort serial_number_word2; /* 19 Board serial number word 2 */
2234 ushort serial_number_word3; /* 20 Board serial number word 3 */
2235 ushort check_sum; /* 21 EEP check sum */
2236 uchar oem_name[16]; /* 22 OEM name */
2237 ushort dvc_err_code; /* 30 last device driver error code */
2238 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2239 ushort adv_err_addr; /* 32 last uc error address */
2240 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2241 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2242 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2243 ushort reserved36; /* 36 reserved */
2244 ushort reserved37; /* 37 reserved */
2245 ushort reserved38; /* 38 reserved */
2246 ushort reserved39; /* 39 reserved */
2247 ushort reserved40; /* 40 reserved */
2248 ushort reserved41; /* 41 reserved */
2249 ushort reserved42; /* 42 reserved */
2250 ushort reserved43; /* 43 reserved */
2251 ushort reserved44; /* 44 reserved */
2252 ushort reserved45; /* 45 reserved */
2253 ushort reserved46; /* 46 reserved */
2254 ushort reserved47; /* 47 reserved */
2255 ushort reserved48; /* 48 reserved */
2256 ushort reserved49; /* 49 reserved */
2257 ushort reserved50; /* 50 reserved */
2258 ushort reserved51; /* 51 reserved */
2259 ushort reserved52; /* 52 reserved */
2260 ushort reserved53; /* 53 reserved */
2261 ushort reserved54; /* 54 reserved */
2262 ushort reserved55; /* 55 reserved */
2263 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2264 ushort cisprt_msw; /* 57 CIS PTR MSW */
2265 ushort subsysvid; /* 58 SubSystem Vendor ID */
2266 ushort subsysid; /* 59 SubSystem ID */
2267 ushort reserved60; /* 60 reserved */
2268 ushort reserved61; /* 61 reserved */
2269 ushort reserved62; /* 62 reserved */
2270 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271} ADVEEP_38C0800_CONFIG;
2272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002273typedef struct adveep_38C1600_config {
2274 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002276 ushort cfg_lsw; /* 00 power up initialization */
2277 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
2278 /* clear - Func. 0 INTA, Func. 1 INTB */
2279 /* bit 13 set - Load CIS */
2280 /* bit 14 set - BIOS Enable */
2281 /* bit 15 set - Big Endian Mode */
2282 ushort cfg_msw; /* 01 unused */
2283 ushort disc_enable; /* 02 disconnect enable */
2284 ushort wdtr_able; /* 03 Wide DTR able */
2285 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2286 ushort start_motor; /* 05 send start up motor */
2287 ushort tagqng_able; /* 06 tag queuing able */
2288 ushort bios_scan; /* 07 BIOS device control */
2289 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002291 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2292 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002294 uchar scsi_reset_delay; /* 10 reset delay */
2295 uchar bios_id_lun; /* first boot device scsi id & lun */
2296 /* high nibble is lun */
2297 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002299 uchar termination_se; /* 11 0 - automatic */
2300 /* 1 - low off / high off */
2301 /* 2 - low off / high on */
2302 /* 3 - low on / high on */
2303 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002305 uchar termination_lvd; /* 11 0 - automatic */
2306 /* 1 - low off / high off */
2307 /* 2 - low off / high on */
2308 /* 3 - low on / high on */
2309 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002311 ushort bios_ctrl; /* 12 BIOS control bits */
2312 /* bit 0 BIOS don't act as initiator. */
2313 /* bit 1 BIOS > 1 GB support */
2314 /* bit 2 BIOS > 2 Disk Support */
2315 /* bit 3 BIOS don't support removables */
2316 /* bit 4 BIOS support bootable CD */
2317 /* bit 5 BIOS scan enabled */
2318 /* bit 6 BIOS support multiple LUNs */
2319 /* bit 7 BIOS display of message */
2320 /* bit 8 SCAM disabled */
2321 /* bit 9 Reset SCSI bus during init. */
2322 /* bit 10 Basic Integrity Checking disabled */
2323 /* bit 11 No verbose initialization. */
2324 /* bit 12 SCSI parity enabled */
2325 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
2326 /* bit 14 */
2327 /* bit 15 */
2328 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2329 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2330 uchar max_host_qng; /* 15 maximum host queueing */
2331 uchar max_dvc_qng; /* maximum per device queuing */
2332 ushort dvc_cntl; /* 16 control bit for driver */
2333 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2334 ushort serial_number_word1; /* 18 Board serial number word 1 */
2335 ushort serial_number_word2; /* 19 Board serial number word 2 */
2336 ushort serial_number_word3; /* 20 Board serial number word 3 */
2337 ushort check_sum; /* 21 EEP check sum */
2338 uchar oem_name[16]; /* 22 OEM name */
2339 ushort dvc_err_code; /* 30 last device driver error code */
2340 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2341 ushort adv_err_addr; /* 32 last uc error address */
2342 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2343 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2344 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2345 ushort reserved36; /* 36 reserved */
2346 ushort reserved37; /* 37 reserved */
2347 ushort reserved38; /* 38 reserved */
2348 ushort reserved39; /* 39 reserved */
2349 ushort reserved40; /* 40 reserved */
2350 ushort reserved41; /* 41 reserved */
2351 ushort reserved42; /* 42 reserved */
2352 ushort reserved43; /* 43 reserved */
2353 ushort reserved44; /* 44 reserved */
2354 ushort reserved45; /* 45 reserved */
2355 ushort reserved46; /* 46 reserved */
2356 ushort reserved47; /* 47 reserved */
2357 ushort reserved48; /* 48 reserved */
2358 ushort reserved49; /* 49 reserved */
2359 ushort reserved50; /* 50 reserved */
2360 ushort reserved51; /* 51 reserved */
2361 ushort reserved52; /* 52 reserved */
2362 ushort reserved53; /* 53 reserved */
2363 ushort reserved54; /* 54 reserved */
2364 ushort reserved55; /* 55 reserved */
2365 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2366 ushort cisprt_msw; /* 57 CIS PTR MSW */
2367 ushort subsysvid; /* 58 SubSystem Vendor ID */
2368 ushort subsysid; /* 59 SubSystem ID */
2369 ushort reserved60; /* 60 reserved */
2370 ushort reserved61; /* 61 reserved */
2371 ushort reserved62; /* 62 reserved */
2372 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373} ADVEEP_38C1600_CONFIG;
2374
2375/*
2376 * EEPROM Commands
2377 */
2378#define ASC_EEP_CMD_DONE 0x0200
2379#define ASC_EEP_CMD_DONE_ERR 0x0001
2380
2381/* cfg_word */
2382#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
2383
2384/* bios_ctrl */
2385#define BIOS_CTRL_BIOS 0x0001
2386#define BIOS_CTRL_EXTENDED_XLAT 0x0002
2387#define BIOS_CTRL_GT_2_DISK 0x0004
2388#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
2389#define BIOS_CTRL_BOOTABLE_CD 0x0010
2390#define BIOS_CTRL_MULTIPLE_LUN 0x0040
2391#define BIOS_CTRL_DISPLAY_MSG 0x0080
2392#define BIOS_CTRL_NO_SCAM 0x0100
2393#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
2394#define BIOS_CTRL_INIT_VERBOSE 0x0800
2395#define BIOS_CTRL_SCSI_PARITY 0x1000
2396#define BIOS_CTRL_AIPP_DIS 0x2000
2397
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002398#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
2399#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002401#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2402#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403
2404/*
2405 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
2406 * a special 16K Adv Library and Microcode version. After the issue is
2407 * resolved, should restore 32K support.
2408 *
2409 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
2410 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002411#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2412#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
2413#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414
2415/*
2416 * Byte I/O register address from base of 'iop_base'.
2417 */
2418#define IOPB_INTR_STATUS_REG 0x00
2419#define IOPB_CHIP_ID_1 0x01
2420#define IOPB_INTR_ENABLES 0x02
2421#define IOPB_CHIP_TYPE_REV 0x03
2422#define IOPB_RES_ADDR_4 0x04
2423#define IOPB_RES_ADDR_5 0x05
2424#define IOPB_RAM_DATA 0x06
2425#define IOPB_RES_ADDR_7 0x07
2426#define IOPB_FLAG_REG 0x08
2427#define IOPB_RES_ADDR_9 0x09
2428#define IOPB_RISC_CSR 0x0A
2429#define IOPB_RES_ADDR_B 0x0B
2430#define IOPB_RES_ADDR_C 0x0C
2431#define IOPB_RES_ADDR_D 0x0D
2432#define IOPB_SOFT_OVER_WR 0x0E
2433#define IOPB_RES_ADDR_F 0x0F
2434#define IOPB_MEM_CFG 0x10
2435#define IOPB_RES_ADDR_11 0x11
2436#define IOPB_GPIO_DATA 0x12
2437#define IOPB_RES_ADDR_13 0x13
2438#define IOPB_FLASH_PAGE 0x14
2439#define IOPB_RES_ADDR_15 0x15
2440#define IOPB_GPIO_CNTL 0x16
2441#define IOPB_RES_ADDR_17 0x17
2442#define IOPB_FLASH_DATA 0x18
2443#define IOPB_RES_ADDR_19 0x19
2444#define IOPB_RES_ADDR_1A 0x1A
2445#define IOPB_RES_ADDR_1B 0x1B
2446#define IOPB_RES_ADDR_1C 0x1C
2447#define IOPB_RES_ADDR_1D 0x1D
2448#define IOPB_RES_ADDR_1E 0x1E
2449#define IOPB_RES_ADDR_1F 0x1F
2450#define IOPB_DMA_CFG0 0x20
2451#define IOPB_DMA_CFG1 0x21
2452#define IOPB_TICKLE 0x22
2453#define IOPB_DMA_REG_WR 0x23
2454#define IOPB_SDMA_STATUS 0x24
2455#define IOPB_SCSI_BYTE_CNT 0x25
2456#define IOPB_HOST_BYTE_CNT 0x26
2457#define IOPB_BYTE_LEFT_TO_XFER 0x27
2458#define IOPB_BYTE_TO_XFER_0 0x28
2459#define IOPB_BYTE_TO_XFER_1 0x29
2460#define IOPB_BYTE_TO_XFER_2 0x2A
2461#define IOPB_BYTE_TO_XFER_3 0x2B
2462#define IOPB_ACC_GRP 0x2C
2463#define IOPB_RES_ADDR_2D 0x2D
2464#define IOPB_DEV_ID 0x2E
2465#define IOPB_RES_ADDR_2F 0x2F
2466#define IOPB_SCSI_DATA 0x30
2467#define IOPB_RES_ADDR_31 0x31
2468#define IOPB_RES_ADDR_32 0x32
2469#define IOPB_SCSI_DATA_HSHK 0x33
2470#define IOPB_SCSI_CTRL 0x34
2471#define IOPB_RES_ADDR_35 0x35
2472#define IOPB_RES_ADDR_36 0x36
2473#define IOPB_RES_ADDR_37 0x37
2474#define IOPB_RAM_BIST 0x38
2475#define IOPB_PLL_TEST 0x39
2476#define IOPB_PCI_INT_CFG 0x3A
2477#define IOPB_RES_ADDR_3B 0x3B
2478#define IOPB_RFIFO_CNT 0x3C
2479#define IOPB_RES_ADDR_3D 0x3D
2480#define IOPB_RES_ADDR_3E 0x3E
2481#define IOPB_RES_ADDR_3F 0x3F
2482
2483/*
2484 * Word I/O register address from base of 'iop_base'.
2485 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002486#define IOPW_CHIP_ID_0 0x00 /* CID0 */
2487#define IOPW_CTRL_REG 0x02 /* CC */
2488#define IOPW_RAM_ADDR 0x04 /* LA */
2489#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002491#define IOPW_RISC_CSR 0x0A /* CSR */
2492#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
2493#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002495#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002497#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002499#define IOPW_EE_CMD 0x1A /* EC */
2500#define IOPW_EE_DATA 0x1C /* ED */
2501#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002503#define IOPW_Q_BASE 0x22 /* QB */
2504#define IOPW_QP 0x24 /* QP */
2505#define IOPW_IX 0x26 /* IX */
2506#define IOPW_SP 0x28 /* SP */
2507#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508#define IOPW_RES_ADDR_2C 0x2C
2509#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002510#define IOPW_SCSI_DATA 0x30 /* SD */
2511#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
2512#define IOPW_SCSI_CTRL 0x34 /* SC */
2513#define IOPW_HSHK_CFG 0x36 /* HCFG */
2514#define IOPW_SXFR_STATUS 0x36 /* SXS */
2515#define IOPW_SXFR_CNTL 0x38 /* SXL */
2516#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002518#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519
2520/*
2521 * Doubleword I/O register address from base of 'iop_base'.
2522 */
2523#define IOPDW_RES_ADDR_0 0x00
2524#define IOPDW_RAM_DATA 0x04
2525#define IOPDW_RES_ADDR_8 0x08
2526#define IOPDW_RES_ADDR_C 0x0C
2527#define IOPDW_RES_ADDR_10 0x10
2528#define IOPDW_COMMA 0x14
2529#define IOPDW_COMMB 0x18
2530#define IOPDW_RES_ADDR_1C 0x1C
2531#define IOPDW_SDMA_ADDR0 0x20
2532#define IOPDW_SDMA_ADDR1 0x24
2533#define IOPDW_SDMA_COUNT 0x28
2534#define IOPDW_SDMA_ERROR 0x2C
2535#define IOPDW_RDMA_ADDR0 0x30
2536#define IOPDW_RDMA_ADDR1 0x34
2537#define IOPDW_RDMA_COUNT 0x38
2538#define IOPDW_RDMA_ERROR 0x3C
2539
2540#define ADV_CHIP_ID_BYTE 0x25
2541#define ADV_CHIP_ID_WORD 0x04C1
2542
2543#define ADV_SC_SCSI_BUS_RESET 0x2000
2544
2545#define ADV_INTR_ENABLE_HOST_INTR 0x01
2546#define ADV_INTR_ENABLE_SEL_INTR 0x02
2547#define ADV_INTR_ENABLE_DPR_INTR 0x04
2548#define ADV_INTR_ENABLE_RTA_INTR 0x08
2549#define ADV_INTR_ENABLE_RMA_INTR 0x10
2550#define ADV_INTR_ENABLE_RST_INTR 0x20
2551#define ADV_INTR_ENABLE_DPE_INTR 0x40
2552#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
2553
2554#define ADV_INTR_STATUS_INTRA 0x01
2555#define ADV_INTR_STATUS_INTRB 0x02
2556#define ADV_INTR_STATUS_INTRC 0x04
2557
2558#define ADV_RISC_CSR_STOP (0x0000)
2559#define ADV_RISC_TEST_COND (0x2000)
2560#define ADV_RISC_CSR_RUN (0x4000)
2561#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
2562
2563#define ADV_CTRL_REG_HOST_INTR 0x0100
2564#define ADV_CTRL_REG_SEL_INTR 0x0200
2565#define ADV_CTRL_REG_DPR_INTR 0x0400
2566#define ADV_CTRL_REG_RTA_INTR 0x0800
2567#define ADV_CTRL_REG_RMA_INTR 0x1000
2568#define ADV_CTRL_REG_RES_BIT14 0x2000
2569#define ADV_CTRL_REG_DPE_INTR 0x4000
2570#define ADV_CTRL_REG_POWER_DONE 0x8000
2571#define ADV_CTRL_REG_ANY_INTR 0xFF00
2572
2573#define ADV_CTRL_REG_CMD_RESET 0x00C6
2574#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
2575#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
2576#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
2577#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
2578
2579#define ADV_TICKLE_NOP 0x00
2580#define ADV_TICKLE_A 0x01
2581#define ADV_TICKLE_B 0x02
2582#define ADV_TICKLE_C 0x03
2583
2584#define ADV_SCSI_CTRL_RSTOUT 0x2000
2585
2586#define AdvIsIntPending(port) \
2587 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
2588
2589/*
2590 * SCSI_CFG0 Register bit definitions
2591 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002592#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
2593#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
2594#define EVEN_PARITY 0x1000 /* Select Even Parity */
2595#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
2596#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
2597#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
2598#define SCAM_EN 0x0080 /* Enable SCAM selection */
2599#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
2600#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
2601#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
2602#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603
2604/*
2605 * SCSI_CFG1 Register bit definitions
2606 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002607#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
2608#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
2609#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
2610#define FILTER_SEL 0x0C00 /* Filter Period Selection */
2611#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
2612#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
2613#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
2614#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
2615#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
2616#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
2617#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
2618#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
2619#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
2620#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
2621#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622
2623/*
2624 * Addendum for ASC-38C0800 Chip
2625 *
2626 * The ASC-38C1600 Chip uses the same definitions except that the
2627 * bus mode override bits [12:10] have been moved to byte register
2628 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
2629 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
2630 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
2631 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
2632 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
2633 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002634#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
2635#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
2636#define HVD 0x1000 /* HVD Device Detect */
2637#define LVD 0x0800 /* LVD Device Detect */
2638#define SE 0x0400 /* SE Device Detect */
2639#define TERM_LVD 0x00C0 /* LVD Termination Bits */
2640#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
2641#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
2642#define TERM_SE 0x0030 /* SE Termination Bits */
2643#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
2644#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
2645#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
2646#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
2647#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
2648#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
2649#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
2650#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651
2652#define CABLE_ILLEGAL_A 0x7
2653 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
2654
2655#define CABLE_ILLEGAL_B 0xB
2656 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
2657
2658/*
2659 * MEM_CFG Register bit definitions
2660 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002661#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
2662#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
2663#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
2664#define RAM_SZ_2KB 0x00 /* 2 KB */
2665#define RAM_SZ_4KB 0x04 /* 4 KB */
2666#define RAM_SZ_8KB 0x08 /* 8 KB */
2667#define RAM_SZ_16KB 0x0C /* 16 KB */
2668#define RAM_SZ_32KB 0x10 /* 32 KB */
2669#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
2671/*
2672 * DMA_CFG0 Register bit definitions
2673 *
2674 * This register is only accessible to the host.
2675 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002676#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
2677#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
2678#define FIFO_THRESH_16B 0x00 /* 16 bytes */
2679#define FIFO_THRESH_32B 0x20 /* 32 bytes */
2680#define FIFO_THRESH_48B 0x30 /* 48 bytes */
2681#define FIFO_THRESH_64B 0x40 /* 64 bytes */
2682#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
2683#define FIFO_THRESH_96B 0x60 /* 96 bytes */
2684#define FIFO_THRESH_112B 0x70 /* 112 bytes */
2685#define START_CTL 0x0C /* DMA start conditions */
2686#define START_CTL_TH 0x00 /* Wait threshold level (default) */
2687#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
2688#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
2689#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
2690#define READ_CMD 0x03 /* Memory Read Method */
2691#define READ_CMD_MR 0x00 /* Memory Read */
2692#define READ_CMD_MRL 0x02 /* Memory Read Long */
2693#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694
2695/*
2696 * ASC-38C0800 RAM BIST Register bit definitions
2697 */
2698#define RAM_TEST_MODE 0x80
2699#define PRE_TEST_MODE 0x40
2700#define NORMAL_MODE 0x00
2701#define RAM_TEST_DONE 0x10
2702#define RAM_TEST_STATUS 0x0F
2703#define RAM_TEST_HOST_ERROR 0x08
2704#define RAM_TEST_INTRAM_ERROR 0x04
2705#define RAM_TEST_RISC_ERROR 0x02
2706#define RAM_TEST_SCSI_ERROR 0x01
2707#define RAM_TEST_SUCCESS 0x00
2708#define PRE_TEST_VALUE 0x05
2709#define NORMAL_VALUE 0x00
2710
2711/*
2712 * ASC38C1600 Definitions
2713 *
2714 * IOPB_PCI_INT_CFG Bit Field Definitions
2715 */
2716
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002717#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718
2719/*
2720 * Bit 1 can be set to change the interrupt for the Function to operate in
2721 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
2722 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
2723 * mode, otherwise the operating mode is undefined.
2724 */
2725#define TOTEMPOLE 0x02
2726
2727/*
2728 * Bit 0 can be used to change the Int Pin for the Function. The value is
2729 * 0 by default for both Functions with Function 0 using INT A and Function
2730 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
2731 * INT A is used.
2732 *
2733 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
2734 * value specified in the PCI Configuration Space.
2735 */
2736#define INTAB 0x01
2737
2738/* a_advlib.h */
2739
2740/*
2741 * Adv Library Status Definitions
2742 */
2743#define ADV_TRUE 1
2744#define ADV_FALSE 0
2745#define ADV_NOERROR 1
2746#define ADV_SUCCESS 1
2747#define ADV_BUSY 0
2748#define ADV_ERROR (-1)
2749
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750/*
2751 * ADV_DVC_VAR 'warn_code' values
2752 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002753#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
2754#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
2755#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
2756#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
2757#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002759#define ADV_MAX_TID 15 /* max. target identifier */
2760#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761
2762/*
2763 * Error code values are set in ADV_DVC_VAR 'err_code'.
2764 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002765#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
2766#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
2767#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
2768#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
2769#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
2770#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
2771#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
2772#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
2773#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
2774#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
2775#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
2776#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
2777#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
2778#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779
2780/*
2781 * Fixed locations of microcode operating variables.
2782 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002783#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
2784#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
2785#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
2786#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
2787#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
2788#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
2789#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
2790#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
2791#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
2792#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
2793#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
2794#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
2795#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796#define ASC_MC_CHIP_TYPE 0x009A
2797#define ASC_MC_INTRB_CODE 0x009B
2798#define ASC_MC_WDTR_ABLE 0x009C
2799#define ASC_MC_SDTR_ABLE 0x009E
2800#define ASC_MC_TAGQNG_ABLE 0x00A0
2801#define ASC_MC_DISC_ENABLE 0x00A2
2802#define ASC_MC_IDLE_CMD_STATUS 0x00A4
2803#define ASC_MC_IDLE_CMD 0x00A6
2804#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
2805#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
2806#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
2807#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
2808#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
2809#define ASC_MC_SDTR_DONE 0x00B6
2810#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
2811#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
2812#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002813#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002815#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816#define ASC_MC_ICQ 0x0160
2817#define ASC_MC_IRQ 0x0164
2818#define ASC_MC_PPR_ABLE 0x017A
2819
2820/*
2821 * BIOS LRAM variable absolute offsets.
2822 */
2823#define BIOS_CODESEG 0x54
2824#define BIOS_CODELEN 0x56
2825#define BIOS_SIGNATURE 0x58
2826#define BIOS_VERSION 0x5A
2827
2828/*
2829 * Microcode Control Flags
2830 *
2831 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
2832 * and handled by the microcode.
2833 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002834#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
2835#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836
2837/*
2838 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
2839 */
2840#define HSHK_CFG_WIDE_XFR 0x8000
2841#define HSHK_CFG_RATE 0x0F00
2842#define HSHK_CFG_OFFSET 0x001F
2843
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002844#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
2845#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
2846#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
2847#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002849#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2850#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2851#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2852#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2853#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002855#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2856#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2857#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2858#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2859#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860/*
2861 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2862 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2863 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002864#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2865#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866
2867/*
2868 * All fields here are accessed by the board microcode and need to be
2869 * little-endian.
2870 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002871typedef struct adv_carr_t {
2872 ADV_VADDR carr_va; /* Carrier Virtual Address */
2873 ADV_PADDR carr_pa; /* Carrier Physical Address */
2874 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2875 /*
2876 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2877 *
2878 * next_vpa [3:1] Reserved Bits
2879 * next_vpa [0] Done Flag set in Response Queue.
2880 */
2881 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882} ADV_CARR_T;
2883
2884/*
2885 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2886 */
2887#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2888
2889#define ASC_RQ_DONE 0x00000001
2890#define ASC_RQ_GOOD 0x00000002
2891#define ASC_CQ_STOPPER 0x00000000
2892
2893#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2894
2895#define ADV_CARRIER_NUM_PAGE_CROSSING \
2896 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2897 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2898
2899#define ADV_CARRIER_BUFSIZE \
2900 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2901
2902/*
2903 * ASC_SCSI_REQ_Q 'a_flag' definitions
2904 *
2905 * The Adv Library should limit use to the lower nibble (4 bits) of
2906 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2907 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002908#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2909#define ADV_SCSIQ_DONE 0x02 /* request done */
2910#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002912#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2913#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2914#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915
2916/*
2917 * Adapter temporary configuration structure
2918 *
2919 * This structure can be discarded after initialization. Don't add
2920 * fields here needed after initialization.
2921 *
2922 * Field naming convention:
2923 *
2924 * *_enable indicates the field enables or disables a feature. The
2925 * value of the field is never reset.
2926 */
2927typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002928 ushort disc_enable; /* enable disconnection */
2929 uchar chip_version; /* chip version */
2930 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2931 ushort lib_version; /* Adv Library version number */
2932 ushort control_flag; /* Microcode Control Flag */
2933 ushort mcode_date; /* Microcode date */
2934 ushort mcode_version; /* Microcode version */
2935 ushort pci_slot_info; /* high byte device/function number */
2936 /* bits 7-3 device num., bits 2-0 function num. */
2937 /* low byte bus num. */
2938 ushort serial1; /* EEPROM serial number word 1 */
2939 ushort serial2; /* EEPROM serial number word 2 */
2940 ushort serial3; /* EEPROM serial number word 3 */
2941 struct device *dev; /* pointer to the pci dev structure for this board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942} ADV_DVC_CFG;
2943
2944struct adv_dvc_var;
2945struct adv_scsi_req_q;
2946
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002947typedef void (*ADV_ISR_CALLBACK)
2948 (struct adv_dvc_var *, struct adv_scsi_req_q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002950typedef void (*ADV_ASYNC_CALLBACK)
2951 (struct adv_dvc_var *, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952
2953/*
2954 * Adapter operation variable structure.
2955 *
2956 * One structure is required per host adapter.
2957 *
2958 * Field naming convention:
2959 *
2960 * *_able indicates both whether a feature should be enabled or disabled
2961 * and whether a device isi capable of the feature. At initialization
2962 * this field may be set, but later if a device is found to be incapable
2963 * of the feature, the field is cleared.
2964 */
2965typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002966 AdvPortAddr iop_base; /* I/O port address */
2967 ushort err_code; /* fatal error code */
2968 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
2969 ADV_ISR_CALLBACK isr_callback;
2970 ADV_ASYNC_CALLBACK async_callback;
2971 ushort wdtr_able; /* try WDTR for a device */
2972 ushort sdtr_able; /* try SDTR for a device */
2973 ushort ultra_able; /* try SDTR Ultra speed for a device */
2974 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2975 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2976 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2977 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2978 ushort tagqng_able; /* try tagged queuing with a device */
2979 ushort ppr_able; /* PPR message capable per TID bitmask. */
2980 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2981 ushort start_motor; /* start motor command allowed */
2982 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2983 uchar chip_no; /* should be assigned by caller */
2984 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2985 uchar irq_no; /* IRQ number */
2986 ushort no_scam; /* scam_tolerant of EEPROM */
2987 struct asc_board *drv_ptr; /* driver pointer to private structure */
2988 uchar chip_scsi_id; /* chip SCSI target ID */
2989 uchar chip_type;
2990 uchar bist_err_code;
2991 ADV_CARR_T *carrier_buf;
2992 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2993 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2994 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2995 ushort carr_pending_cnt; /* Count of pending carriers. */
2996 /*
2997 * Note: The following fields will not be used after initialization. The
2998 * driver may discard the buffer after initialization is done.
2999 */
3000 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001} ADV_DVC_VAR;
3002
3003#define NO_OF_SG_PER_BLOCK 15
3004
3005typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003006 uchar reserved1;
3007 uchar reserved2;
3008 uchar reserved3;
3009 uchar sg_cnt; /* Valid entries in block. */
3010 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
3011 struct {
3012 ADV_PADDR sg_addr; /* SG element address. */
3013 ADV_DCNT sg_count; /* SG element count. */
3014 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015} ADV_SG_BLOCK;
3016
3017/*
3018 * ADV_SCSI_REQ_Q - microcode request structure
3019 *
3020 * All fields in this structure up to byte 60 are used by the microcode.
3021 * The microcode makes assumptions about the size and ordering of fields
3022 * in this structure. Do not change the structure definition here without
3023 * coordinating the change with the microcode.
3024 *
3025 * All fields accessed by microcode must be maintained in little_endian
3026 * order.
3027 */
3028typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003029 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
3030 uchar target_cmd;
3031 uchar target_id; /* Device target identifier. */
3032 uchar target_lun; /* Device target logical unit number. */
3033 ADV_PADDR data_addr; /* Data buffer physical address. */
3034 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
3035 ADV_PADDR sense_addr;
3036 ADV_PADDR carr_pa;
3037 uchar mflag;
3038 uchar sense_len;
3039 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
3040 uchar scsi_cntl;
3041 uchar done_status; /* Completion status. */
3042 uchar scsi_status; /* SCSI status byte. */
3043 uchar host_status; /* Ucode host status. */
3044 uchar sg_working_ix;
3045 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
3046 ADV_PADDR sg_real_addr; /* SG list physical address. */
3047 ADV_PADDR scsiq_rptr;
3048 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
3049 ADV_VADDR scsiq_ptr;
3050 ADV_VADDR carr_va;
3051 /*
3052 * End of microcode structure - 60 bytes. The rest of the structure
3053 * is used by the Adv Library and ignored by the microcode.
3054 */
3055 ADV_VADDR srb_ptr;
3056 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
3057 char *vdata_addr; /* Data buffer virtual address. */
3058 uchar a_flag;
3059 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060} ADV_SCSI_REQ_Q;
3061
3062/*
3063 * Microcode idle loop commands
3064 */
3065#define IDLE_CMD_COMPLETED 0
3066#define IDLE_CMD_STOP_CHIP 0x0001
3067#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
3068#define IDLE_CMD_SEND_INT 0x0004
3069#define IDLE_CMD_ABORT 0x0008
3070#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003071#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
3072#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073#define IDLE_CMD_SCSIREQ 0x0080
3074
3075#define IDLE_CMD_STATUS_SUCCESS 0x0001
3076#define IDLE_CMD_STATUS_FAILURE 0x0002
3077
3078/*
3079 * AdvSendIdleCmd() flag definitions.
3080 */
3081#define ADV_NOWAIT 0x01
3082
3083/*
3084 * Wait loop time out values.
3085 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003086#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
3087#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
3088#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
3089#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
3090#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003092#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
3093#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
3094#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
3095#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003097#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
3099/*
3100 * Device drivers must define the following functions.
3101 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003102static inline ulong DvcEnterCritical(void);
3103static inline void DvcLeaveCritical(ulong);
3104static void DvcSleepMilliSecond(ADV_DCNT);
3105static uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
3106static void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
3107static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
3108 uchar *, ASC_SDCNT *, int);
3109static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110
3111/*
3112 * Adv Library functions available to drivers.
3113 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003114static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3115static int AdvISR(ADV_DVC_VAR *);
3116static int AdvInitGetConfig(ADV_DVC_VAR *);
3117static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
3118static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
3119static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
3120static int AdvResetChipAndSB(ADV_DVC_VAR *);
3121static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
3123/*
3124 * Internal Adv Library functions.
3125 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003126static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
3127static void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3128static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
3129static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
3130static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
3131static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3132static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3133static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3134static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3135static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3136static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3137static void AdvWaitEEPCmd(AdvPortAddr);
3138static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139
3140/*
3141 * PCI Bus Definitions
3142 */
3143#define AscPCICmdRegBits_BusMastering 0x0007
3144#define AscPCICmdRegBits_ParErrRespCtrl 0x0040
3145
3146/* Read byte from a register. */
3147#define AdvReadByteRegister(iop_base, reg_off) \
3148 (ADV_MEM_READB((iop_base) + (reg_off)))
3149
3150/* Write byte to a register. */
3151#define AdvWriteByteRegister(iop_base, reg_off, byte) \
3152 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
3153
3154/* Read word (2 bytes) from a register. */
3155#define AdvReadWordRegister(iop_base, reg_off) \
3156 (ADV_MEM_READW((iop_base) + (reg_off)))
3157
3158/* Write word (2 bytes) to a register. */
3159#define AdvWriteWordRegister(iop_base, reg_off, word) \
3160 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
3161
3162/* Write dword (4 bytes) to a register. */
3163#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
3164 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
3165
3166/* Read byte from LRAM. */
3167#define AdvReadByteLram(iop_base, addr, byte) \
3168do { \
3169 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3170 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
3171} while (0)
3172
3173/* Write byte to LRAM. */
3174#define AdvWriteByteLram(iop_base, addr, byte) \
3175 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3176 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
3177
3178/* Read word (2 bytes) from LRAM. */
3179#define AdvReadWordLram(iop_base, addr, word) \
3180do { \
3181 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3182 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
3183} while (0)
3184
3185/* Write word (2 bytes) to LRAM. */
3186#define AdvWriteWordLram(iop_base, addr, word) \
3187 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3188 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3189
3190/* Write little-endian double word (4 bytes) to LRAM */
3191/* Because of unspecified C language ordering don't use auto-increment. */
3192#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
3193 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3194 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3195 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
3196 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
3197 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3198 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
3199
3200/* Read word (2 bytes) from LRAM assuming that the address is already set. */
3201#define AdvReadWordAutoIncLram(iop_base) \
3202 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
3203
3204/* Write word (2 bytes) to LRAM assuming that the address is already set. */
3205#define AdvWriteWordAutoIncLram(iop_base, word) \
3206 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3207
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208/*
3209 * Define macro to check for Condor signature.
3210 *
3211 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
3212 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
3213 */
3214#define AdvFindSignature(iop_base) \
3215 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
3216 ADV_CHIP_ID_BYTE) && \
3217 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
3218 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
3219
3220/*
3221 * Define macro to Return the version number of the chip at 'iop_base'.
3222 *
3223 * The second parameter 'bus_type' is currently unused.
3224 */
3225#define AdvGetChipVersion(iop_base, bus_type) \
3226 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
3227
3228/*
3229 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
3230 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
3231 *
3232 * If the request has not yet been sent to the device it will simply be
3233 * aborted from RISC memory. If the request is disconnected it will be
3234 * aborted on reselection by sending an Abort Message to the target ID.
3235 *
3236 * Return value:
3237 * ADV_TRUE(1) - Queue was successfully aborted.
3238 * ADV_FALSE(0) - Queue was not found on the active queue list.
3239 */
3240#define AdvAbortQueue(asc_dvc, scsiq) \
3241 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
3242 (ADV_DCNT) (scsiq))
3243
3244/*
3245 * Send a Bus Device Reset Message to the specified target ID.
3246 *
3247 * All outstanding commands will be purged if sending the
3248 * Bus Device Reset Message is successful.
3249 *
3250 * Return Value:
3251 * ADV_TRUE(1) - All requests on the target are purged.
3252 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
3253 * are not purged.
3254 */
3255#define AdvResetDevice(asc_dvc, target_id) \
3256 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
3257 (ADV_DCNT) (target_id))
3258
3259/*
3260 * SCSI Wide Type definition.
3261 */
3262#define ADV_SCSI_BIT_ID_TYPE ushort
3263
3264/*
3265 * AdvInitScsiTarget() 'cntl_flag' options.
3266 */
3267#define ADV_SCAN_LUN 0x01
3268#define ADV_CAPINFO_NOLUN 0x02
3269
3270/*
3271 * Convert target id to target id bit mask.
3272 */
3273#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
3274
3275/*
3276 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
3277 */
3278
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003279#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280#define QD_NO_ERROR 0x01
3281#define QD_ABORTED_BY_HOST 0x02
3282#define QD_WITH_ERROR 0x04
3283
3284#define QHSTA_NO_ERROR 0x00
3285#define QHSTA_M_SEL_TIMEOUT 0x11
3286#define QHSTA_M_DATA_OVER_RUN 0x12
3287#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
3288#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003289#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
3290#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
3291#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
3292#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
3293#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
3294#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
3295#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003297#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
3298#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
3299#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
3300#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
3301#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
3302#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
3303#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
3304#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305#define QHSTA_M_WTM_TIMEOUT 0x41
3306#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
3307#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
3308#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003309#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
3310#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
3311#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
3313/*
3314 * Default EEPROM Configuration structure defined in a_init.c.
3315 */
3316static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
3317static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
3318static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
3319
3320/*
3321 * DvcGetPhyAddr() flag arguments
3322 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003323#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
3324#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
3325#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
3326#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
3327#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
3328#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
3330/* Return the address that is aligned at the next doubleword >= to 'addr'. */
3331#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
3332#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
3333#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
3334
3335/*
3336 * Total contiguous memory needed for driver SG blocks.
3337 *
3338 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
3339 * number of scatter-gather elements the driver supports in a
3340 * single request.
3341 */
3342
3343#define ADV_SG_LIST_MAX_BYTE_SIZE \
3344 (sizeof(ADV_SG_BLOCK) * \
3345 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
3346
3347/*
3348 * Inquiry data structure and bitfield macros
3349 *
3350 * Using bitfields to access the subchar data isn't portable across
3351 * endianness, so instead mask and shift. Only quantities of more
3352 * than 1 bit are shifted, since the others are just tested for true
3353 * or false.
3354 */
3355
3356#define ADV_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
3357#define ADV_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
3358#define ADV_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
3359#define ADV_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
3360#define ADV_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
3361#define ADV_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
3362#define ADV_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
3363#define ADV_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
3364#define ADV_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
3365#define ADV_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
3366#define ADV_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
3367#define ADV_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
3368#define ADV_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
3369#define ADV_INQ_SYNC(inq) ((inq)->flags & 0x10)
3370#define ADV_INQ_WIDE16(inq) ((inq)->flags & 0x20)
3371#define ADV_INQ_WIDE32(inq) ((inq)->flags & 0x40)
3372#define ADV_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
3373#define ADV_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
3374#define ADV_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
3375#define ADV_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
3376
3377typedef struct {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003378 uchar periph; /* peripheral device type [0:4] */
3379 /* peripheral qualifier [5:7] */
3380 uchar devtype; /* device type modifier (for SCSI I) [0:6] */
3381 /* RMB - removable medium bit [7] */
3382 uchar ver; /* ANSI approved version [0:2] */
3383 /* ECMA version [3:5] */
3384 /* ISO version [6:7] */
3385 uchar byte3; /* response data format [0:3] */
3386 /* 0 SCSI 1 */
3387 /* 1 CCS */
3388 /* 2 SCSI-2 */
3389 /* 3-F reserved */
3390 /* reserved [4:5] */
3391 /* terminate I/O process bit (see 5.6.22) [6] */
3392 /* asynch. event notification (processor) [7] */
3393 uchar add_len; /* additional length */
3394 uchar res1; /* reserved */
3395 uchar res2; /* reserved */
3396 uchar flags; /* soft reset implemented [0] */
3397 /* command queuing [1] */
3398 /* reserved [2] */
3399 /* linked command for this logical unit [3] */
3400 /* synchronous data transfer [4] */
3401 /* wide bus 16 bit data transfer [5] */
3402 /* wide bus 32 bit data transfer [6] */
3403 /* relative addressing mode [7] */
3404 uchar vendor_id[8]; /* vendor identification */
3405 uchar product_id[16]; /* product identification */
3406 uchar product_rev_level[4]; /* product revision level */
3407 uchar vendor_specific[20]; /* vendor specific */
3408 uchar info; /* information unit supported [0] */
3409 /* quick arbitrate supported [1] */
3410 /* clocking field [2:3] */
3411 /* reserved [4:7] */
3412 uchar res3; /* reserved */
3413} ADV_SCSI_INQUIRY; /* 58 bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414
3415/*
3416 * --- Driver Constants and Macros
3417 */
3418
3419#define ASC_NUM_BOARD_SUPPORTED 16
3420#define ASC_NUM_IOPORT_PROBE 4
Matthew Wilcox78e77d82007-07-29 21:46:15 -06003421#define ASC_NUM_BUS 3
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422
3423/* Reference Scsi_Host hostdata */
3424#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
3425
3426/* asc_board_t flags */
3427#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003428#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429#define ASC_SELECT_QUEUE_DEPTHS 0x08
3430
3431#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
3432#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
3433
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003434#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003436#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437
3438#ifdef CONFIG_PROC_FS
3439/* /proc/scsi/advansys/[0...] related definitions */
3440#define ASC_PRTBUF_SIZE 2048
3441#define ASC_PRTLINE_SIZE 160
3442
3443#define ASC_PRT_NEXT() \
3444 if (cp) { \
3445 totlen += len; \
3446 leftlen -= len; \
3447 if (leftlen == 0) { \
3448 return totlen; \
3449 } \
3450 cp += len; \
3451 }
3452#endif /* CONFIG_PROC_FS */
3453
3454/* Asc Library return codes */
3455#define ASC_TRUE 1
3456#define ASC_FALSE 0
3457#define ASC_NOERROR 1
3458#define ASC_BUSY 0
3459#define ASC_ERROR (-1)
3460
3461/* struct scsi_cmnd function return codes */
3462#define STATUS_BYTE(byte) (byte)
3463#define MSG_BYTE(byte) ((byte) << 8)
3464#define HOST_BYTE(byte) ((byte) << 16)
3465#define DRIVER_BYTE(byte) ((byte) << 24)
3466
3467/*
3468 * The following definitions and macros are OS independent interfaces to
3469 * the queue functions:
3470 * REQ - SCSI request structure
3471 * REQP - pointer to SCSI request structure
3472 * REQPTID(reqp) - reqp's target id
3473 * REQPNEXT(reqp) - reqp's next pointer
3474 * REQPNEXTP(reqp) - pointer to reqp's next pointer
3475 * REQPTIME(reqp) - reqp's time stamp value
3476 * REQTIMESTAMP() - system time stamp value
3477 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003478typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
3480#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
3481#define REQPTID(reqp) ((reqp)->device->id)
3482#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
3483#define REQTIMESTAMP() (jiffies)
3484
3485#define REQTIMESTAT(function, ascq, reqp, tid) \
3486{ \
3487 /*
3488 * If the request time stamp is less than the system time stamp, then \
3489 * maybe the system time stamp wrapped. Set the request time to zero.\
3490 */ \
3491 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
3492 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
3493 } else { \
3494 /* Indicate an error occurred with the assertion. */ \
3495 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
3496 REQPTIME(reqp) = 0; \
3497 } \
3498 /* Handle first minimum time case without external initialization. */ \
3499 if (((ascq)->q_tot_cnt[tid] == 1) || \
3500 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
3501 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
3502 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
3503 (function), (tid), (ascq)->q_min_tim[tid]); \
3504 } \
3505 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
3506 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
3507 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
3508 (function), tid, (ascq)->q_max_tim[tid]); \
3509 } \
3510 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
3511 /* Reset the time stamp field. */ \
3512 REQPTIME(reqp) = 0; \
3513}
3514
3515/* asc_enqueue() flags */
3516#define ASC_FRONT 1
3517#define ASC_BACK 2
3518
3519/* asc_dequeue_list() argument */
3520#define ASC_TID_ALL (-1)
3521
3522/* Return non-zero, if the queue is empty. */
3523#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
3524
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003526#define ASC_STATS(shost, counter)
3527#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003529#define ASC_STATS(shost, counter) \
3530 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003532#define ASC_STATS_ADD(shost, counter, count) \
3533 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534#endif /* ADVANSYS_STATS */
3535
3536#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
3537
3538/* If the result wraps when calculating tenths, return 0. */
3539#define ASC_TENTHS(num, den) \
3540 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
3541 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
3542
3543/*
3544 * Display a message to the console.
3545 */
3546#define ASC_PRINT(s) \
3547 { \
3548 printk("advansys: "); \
3549 printk(s); \
3550 }
3551
3552#define ASC_PRINT1(s, a1) \
3553 { \
3554 printk("advansys: "); \
3555 printk((s), (a1)); \
3556 }
3557
3558#define ASC_PRINT2(s, a1, a2) \
3559 { \
3560 printk("advansys: "); \
3561 printk((s), (a1), (a2)); \
3562 }
3563
3564#define ASC_PRINT3(s, a1, a2, a3) \
3565 { \
3566 printk("advansys: "); \
3567 printk((s), (a1), (a2), (a3)); \
3568 }
3569
3570#define ASC_PRINT4(s, a1, a2, a3, a4) \
3571 { \
3572 printk("advansys: "); \
3573 printk((s), (a1), (a2), (a3), (a4)); \
3574 }
3575
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576#ifndef ADVANSYS_DEBUG
3577
3578#define ASC_DBG(lvl, s)
3579#define ASC_DBG1(lvl, s, a1)
3580#define ASC_DBG2(lvl, s, a1, a2)
3581#define ASC_DBG3(lvl, s, a1, a2, a3)
3582#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
3583#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
3584#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
3585#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
3586#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3587#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
3588#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3589#define ASC_DBG_PRT_HEX(lvl, name, start, length)
3590#define ASC_DBG_PRT_CDB(lvl, cdb, len)
3591#define ASC_DBG_PRT_SENSE(lvl, sense, len)
3592#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
3593
3594#else /* ADVANSYS_DEBUG */
3595
3596/*
3597 * Debugging Message Levels:
3598 * 0: Errors Only
3599 * 1: High-Level Tracing
3600 * 2-N: Verbose Tracing
3601 */
3602
3603#define ASC_DBG(lvl, s) \
3604 { \
3605 if (asc_dbglvl >= (lvl)) { \
3606 printk(s); \
3607 } \
3608 }
3609
3610#define ASC_DBG1(lvl, s, a1) \
3611 { \
3612 if (asc_dbglvl >= (lvl)) { \
3613 printk((s), (a1)); \
3614 } \
3615 }
3616
3617#define ASC_DBG2(lvl, s, a1, a2) \
3618 { \
3619 if (asc_dbglvl >= (lvl)) { \
3620 printk((s), (a1), (a2)); \
3621 } \
3622 }
3623
3624#define ASC_DBG3(lvl, s, a1, a2, a3) \
3625 { \
3626 if (asc_dbglvl >= (lvl)) { \
3627 printk((s), (a1), (a2), (a3)); \
3628 } \
3629 }
3630
3631#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
3632 { \
3633 if (asc_dbglvl >= (lvl)) { \
3634 printk((s), (a1), (a2), (a3), (a4)); \
3635 } \
3636 }
3637
3638#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
3639 { \
3640 if (asc_dbglvl >= (lvl)) { \
3641 asc_prt_scsi_host(s); \
3642 } \
3643 }
3644
3645#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
3646 { \
3647 if (asc_dbglvl >= (lvl)) { \
3648 asc_prt_scsi_cmnd(s); \
3649 } \
3650 }
3651
3652#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
3653 { \
3654 if (asc_dbglvl >= (lvl)) { \
3655 asc_prt_asc_scsi_q(scsiqp); \
3656 } \
3657 }
3658
3659#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
3660 { \
3661 if (asc_dbglvl >= (lvl)) { \
3662 asc_prt_asc_qdone_info(qdone); \
3663 } \
3664 }
3665
3666#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
3667 { \
3668 if (asc_dbglvl >= (lvl)) { \
3669 asc_prt_adv_scsi_req_q(scsiqp); \
3670 } \
3671 }
3672
3673#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
3674 { \
3675 if (asc_dbglvl >= (lvl)) { \
3676 asc_prt_hex((name), (start), (length)); \
3677 } \
3678 }
3679
3680#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
3681 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
3682
3683#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
3684 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
3685
3686#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
3687 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
3688#endif /* ADVANSYS_DEBUG */
3689
3690#ifndef ADVANSYS_ASSERT
3691#define ASC_ASSERT(a)
3692#else /* ADVANSYS_ASSERT */
3693
3694#define ASC_ASSERT(a) \
3695 { \
3696 if (!(a)) { \
3697 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
3698 __FILE__, __LINE__); \
3699 } \
3700 }
3701
3702#endif /* ADVANSYS_ASSERT */
3703
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704/*
3705 * --- Driver Structures
3706 */
3707
3708#ifdef ADVANSYS_STATS
3709
3710/* Per board statistics structure */
3711struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003712 /* Driver Entrypoint Statistics */
3713 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
3714 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
3715 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
3716 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
3717 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
3718 ADV_DCNT done; /* # calls to request's scsi_done function */
3719 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
3720 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
3721 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
3722 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
3723 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
3724 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
3725 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
3726 ADV_DCNT exe_unknown; /* # unknown returns. */
3727 /* Data Transfer Statistics */
3728 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
3729 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
3730 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
3731 ADV_DCNT sg_elem; /* # scatter-gather elements */
3732 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733};
3734#endif /* ADVANSYS_STATS */
3735
3736/*
3737 * Request queuing structure
3738 */
3739typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003740 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
3741 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
3742 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003744 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
3745 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
3746 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
3747 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
3748 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
3749 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
3750#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751} asc_queue_t;
3752
3753/*
3754 * Adv Library Request Structures
3755 *
3756 * The following two structures are used to process Wide Board requests.
3757 *
3758 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
3759 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
3760 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
3761 * Mid-Level SCSI request structure.
3762 *
3763 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
3764 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
3765 * up to 255 scatter-gather elements may be used per request or
3766 * ADV_SCSI_REQ_Q.
3767 *
3768 * Both structures must be 32 byte aligned.
3769 */
3770typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003771 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
3772 uchar align[32]; /* Sgblock structure padding. */
3773 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774} adv_sgblk_t;
3775
3776typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003777 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
3778 uchar align[32]; /* Request structure padding. */
3779 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
3780 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
3781 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782} adv_req_t;
3783
3784/*
3785 * Structure allocated for each board.
3786 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003787 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 * of the 'Scsi_Host' structure starting at the 'hostdata'
3789 * field. It is guaranteed to be allocated from DMA-able memory.
3790 */
3791typedef struct asc_board {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003792 int id; /* Board Id */
3793 uint flags; /* Board flags */
3794 union {
3795 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
3796 ADV_DVC_VAR adv_dvc_var; /* Wide board */
3797 } dvc_var;
3798 union {
3799 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
3800 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
3801 } dvc_cfg;
3802 ushort asc_n_io_port; /* Number I/O ports. */
3803 asc_queue_t active; /* Active command queue */
3804 asc_queue_t waiting; /* Waiting command queue */
3805 asc_queue_t done; /* Done command queue */
3806 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
3807 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
3808 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
3809 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
3810 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
3811 union {
3812 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
3813 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
3814 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
3815 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
3816 } eep_config;
3817 ulong last_reset; /* Saved last reset time */
3818 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003819 /* /proc/scsi/advansys/[0...] */
3820 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003822 struct asc_stats asc_stats; /* Board statistics */
3823#endif /* ADVANSYS_STATS */
3824 /*
3825 * The following fields are used only for Narrow Boards.
3826 */
3827 /* The following three structures must be in DMA-able memory. */
3828 ASC_SCSI_REQ_Q scsireqq;
3829 ASC_CAP_INFO cap_info;
3830 ASC_SCSI_INQUIRY inquiry;
3831 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3832 /*
3833 * The following fields are used only for Wide Boards.
3834 */
3835 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3836 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06003837 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003838 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3839 adv_req_t *adv_reqp; /* Request structures. */
3840 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3841 ushort bios_signature; /* BIOS Signature. */
3842 ushort bios_version; /* BIOS Version. */
3843 ushort bios_codeseg; /* BIOS Code Segment. */
3844 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845} asc_board_t;
3846
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06003848static int asc_board_count;
3849
3850/* Number of boards detected by advansys_detect */
3851static int asc_legacy_count;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003852static struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853
3854/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003855static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856
3857/*
3858 * Global structures required to issue a command.
3859 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003860static ASC_SCSI_Q asc_scsi_q = { {0} };
3861static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862
Matthew Wilcox78e77d82007-07-29 21:46:15 -06003863/* List of bus types probed in advansys_detect. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003864static ushort asc_bus[ASC_NUM_BUS] __initdata = {
3865 ASC_IS_ISA,
3866 ASC_IS_VL,
3867 ASC_IS_EISA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868};
3869
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003870static int asc_iopflag = ASC_FALSE;
3871static int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872
3873#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003874static char *asc_bus_name[ASC_NUM_BUS] = {
3875 "ASC_IS_ISA",
3876 "ASC_IS_VL",
3877 "ASC_IS_EISA",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878};
3879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003880static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881#endif /* ADVANSYS_DEBUG */
3882
3883/* Declaration for Asc Library internal data referenced by driver. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003884static PortAddr _asc_def_iop_base[];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885
3886/*
3887 * --- Driver Function Prototypes
3888 *
3889 * advansys.h contains function prototypes for functions global to Linux.
3890 */
3891
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003892static int advansys_slave_configure(struct scsi_device *);
3893static void asc_scsi_done_list(struct scsi_cmnd *);
3894static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3895static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3896static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3897static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
3898static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
3899static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3900static void adv_async_callback(ADV_DVC_VAR *, uchar);
3901static void asc_enqueue(asc_queue_t *, REQP, int);
3902static REQP asc_dequeue(asc_queue_t *, int);
3903static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3904static int asc_rmqueue(asc_queue_t *, REQP);
3905static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003907static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3908static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3909static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3910static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3911static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3912static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3913static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3914static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3915static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3916static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917#endif /* CONFIG_PROC_FS */
3918
3919/* Declaration for Asc Library internal functions referenced by driver. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003920static int AscFindSignature(PortAddr);
3921static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922
3923/* Statistics function prototypes. */
3924#ifdef ADVANSYS_STATS
3925#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003926static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3927static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928#endif /* CONFIG_PROC_FS */
3929#endif /* ADVANSYS_STATS */
3930
3931/* Debug function prototypes. */
3932#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003933static void asc_prt_scsi_host(struct Scsi_Host *);
3934static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
3935static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
3936static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
3937static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
3938static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
3939static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
3940static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
3941static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
3942static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
3943static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944#endif /* ADVANSYS_DEBUG */
3945
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946#ifdef CONFIG_PROC_FS
3947/*
3948 * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
3949 *
3950 * *buffer: I/O buffer
3951 * **start: if inout == FALSE pointer into buffer where user read should start
3952 * offset: current offset into a /proc/scsi/advansys/[0...] file
3953 * length: length of buffer
3954 * hostno: Scsi_Host host_no
3955 * inout: TRUE - user is writing; FALSE - user is reading
3956 *
3957 * Return the number of bytes read from or written to a
3958 * /proc/scsi/advansys/[0...] file.
3959 *
3960 * Note: This function uses the per board buffer 'prtbuf' which is
3961 * allocated when the board is initialized in advansys_detect(). The
3962 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
3963 * used to write to the buffer. The way asc_proc_copy() is written
3964 * if 'prtbuf' is too small it will not be overwritten. Instead the
3965 * user just won't get all the available statistics.
3966 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003967static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003969 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003971 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003972 char *cp;
3973 int cplen;
3974 int cnt;
3975 int totcnt;
3976 int leftlen;
3977 char *curbuf;
3978 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003980 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981#endif /* ADVANSYS_STATS */
3982
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003983 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003985 /*
3986 * User write not supported.
3987 */
3988 if (inout == TRUE) {
3989 return (-ENOSYS);
3990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003992 /*
3993 * User read of /proc/scsi/advansys/[0...] file.
3994 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995
Matthew Wilcox2a437952007-07-26 11:00:51 -04003996 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003998 /* Copy read data starting at the beginning of the buffer. */
3999 *start = buffer;
4000 curbuf = buffer;
4001 advoffset = 0;
4002 totcnt = 0;
4003 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004005 /*
4006 * Get board configuration information.
4007 *
4008 * advansys_info() returns the board string from its own static buffer.
4009 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04004010 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004011 strcat(cp, "\n");
4012 cplen = strlen(cp);
4013 /* Copy board information. */
4014 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4015 totcnt += cnt;
4016 leftlen -= cnt;
4017 if (leftlen == 0) {
4018 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4019 return totcnt;
4020 }
4021 advoffset += cplen;
4022 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004024 /*
4025 * Display Wide Board BIOS Information.
4026 */
4027 if (ASC_WIDE_BOARD(boardp)) {
4028 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004029 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004030 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4031 cnt =
4032 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
4033 cplen);
4034 totcnt += cnt;
4035 leftlen -= cnt;
4036 if (leftlen == 0) {
4037 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4038 return totcnt;
4039 }
4040 advoffset += cplen;
4041 curbuf += cnt;
4042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004044 /*
4045 * Display driver information for each device attached to the board.
4046 */
4047 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004048 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004049 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4050 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4051 totcnt += cnt;
4052 leftlen -= cnt;
4053 if (leftlen == 0) {
4054 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4055 return totcnt;
4056 }
4057 advoffset += cplen;
4058 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004060 /*
4061 * Display EEPROM configuration for the board.
4062 */
4063 cp = boardp->prtbuf;
4064 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004065 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004066 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004067 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004068 }
4069 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4070 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4071 totcnt += cnt;
4072 leftlen -= cnt;
4073 if (leftlen == 0) {
4074 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4075 return totcnt;
4076 }
4077 advoffset += cplen;
4078 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004080 /*
4081 * Display driver configuration and information for the board.
4082 */
4083 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004084 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004085 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4086 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4087 totcnt += cnt;
4088 leftlen -= cnt;
4089 if (leftlen == 0) {
4090 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4091 return totcnt;
4092 }
4093 advoffset += cplen;
4094 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095
4096#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004097 /*
4098 * Display driver statistics for the board.
4099 */
4100 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004101 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004102 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4103 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4104 totcnt += cnt;
4105 leftlen -= cnt;
4106 if (leftlen == 0) {
4107 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4108 return totcnt;
4109 }
4110 advoffset += cplen;
4111 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004113 /*
4114 * Display driver statistics for each target.
4115 */
4116 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
4117 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004118 cplen = asc_prt_target_stats(shost, tgt_id, cp,
4119 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004120 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4121 cnt =
4122 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
4123 cplen);
4124 totcnt += cnt;
4125 leftlen -= cnt;
4126 if (leftlen == 0) {
4127 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4128 return totcnt;
4129 }
4130 advoffset += cplen;
4131 curbuf += cnt;
4132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133#endif /* ADVANSYS_STATS */
4134
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004135 /*
4136 * Display Asc Library dynamic configuration information
4137 * for the board.
4138 */
4139 cp = boardp->prtbuf;
4140 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004141 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004142 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004143 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004144 }
4145 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
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004156 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004158 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159}
4160#endif /* CONFIG_PROC_FS */
4161
4162/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 * advansys_info()
4164 *
4165 * Return suitable for printing on the console with the argument
4166 * adapter's configuration information.
4167 *
4168 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
4169 * otherwise the static 'info' array will be overrun.
4170 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004171static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004173 static char info[ASC_INFO_SIZE];
4174 asc_board_t *boardp;
4175 ASC_DVC_VAR *asc_dvc_varp;
4176 ADV_DVC_VAR *adv_dvc_varp;
4177 char *busname;
4178 int iolen;
4179 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004181 boardp = ASC_BOARDP(shost);
4182 if (ASC_NARROW_BOARD(boardp)) {
4183 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
4184 ASC_DBG(1, "advansys_info: begin\n");
4185 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
4186 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
4187 ASC_IS_ISAPNP) {
4188 busname = "ISA PnP";
4189 } else {
4190 busname = "ISA";
4191 }
4192 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4193 sprintf(info,
4194 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
4195 ASC_VERSION, busname,
4196 (ulong)shost->io_port,
4197 (ulong)shost->io_port + boardp->asc_n_io_port -
4198 1, shost->irq, shost->dma_channel);
4199 } else {
4200 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
4201 busname = "VL";
4202 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
4203 busname = "EISA";
4204 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
4205 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
4206 == ASC_IS_PCI_ULTRA) {
4207 busname = "PCI Ultra";
4208 } else {
4209 busname = "PCI";
4210 }
4211 } else {
4212 busname = "?";
4213 ASC_PRINT2
4214 ("advansys_info: board %d: unknown bus type %d\n",
4215 boardp->id, asc_dvc_varp->bus_type);
4216 }
4217 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4218 sprintf(info,
4219 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
4220 ASC_VERSION, busname,
4221 (ulong)shost->io_port,
4222 (ulong)shost->io_port + boardp->asc_n_io_port -
4223 1, shost->irq);
4224 }
4225 } else {
4226 /*
4227 * Wide Adapter Information
4228 *
4229 * Memory-mapped I/O is used instead of I/O space to access
4230 * the adapter, but display the I/O Port range. The Memory
4231 * I/O address is displayed through the driver /proc file.
4232 */
4233 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4234 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4235 iolen = ADV_3550_IOLEN;
4236 widename = "Ultra-Wide";
4237 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4238 iolen = ADV_38C0800_IOLEN;
4239 widename = "Ultra2-Wide";
4240 } else {
4241 iolen = ADV_38C1600_IOLEN;
4242 widename = "Ultra3-Wide";
4243 }
4244 sprintf(info,
4245 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
4246 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
4247 (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
4248 }
4249 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
4250 ASC_DBG(1, "advansys_info: end\n");
4251 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252}
4253
4254/*
4255 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
4256 *
4257 * This function always returns 0. Command return status is saved
4258 * in the 'scp' result field.
4259 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004260static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004261advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004263 struct Scsi_Host *shost;
4264 asc_board_t *boardp;
4265 ulong flags;
4266 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004268 shost = scp->device->host;
4269 boardp = ASC_BOARDP(shost);
4270 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004272 /* host_lock taken by mid-level prior to call but need to protect */
4273 /* against own ISR */
4274 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004276 /*
4277 * Block new commands while handling a reset or abort request.
4278 */
4279 if (boardp->flags & ASC_HOST_IN_RESET) {
4280 ASC_DBG1(1,
4281 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4282 (ulong)scp);
4283 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004285 /*
4286 * Add blocked requests to the board's 'done' queue. The queued
4287 * requests will be completed at the end of the abort or reset
4288 * handling.
4289 */
4290 asc_enqueue(&boardp->done, scp, ASC_BACK);
4291 spin_unlock_irqrestore(&boardp->lock, flags);
4292 return 0;
4293 }
4294
4295 /*
4296 * Attempt to execute any waiting commands for the board.
4297 */
4298 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4299 ASC_DBG(1,
4300 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4301 asc_execute_queue(&boardp->waiting);
4302 }
4303
4304 /*
4305 * Save the function pointer to Linux mid-level 'done' function
4306 * and attempt to execute the command.
4307 *
4308 * If ASC_NOERROR is returned the request has been added to the
4309 * board's 'active' queue and will be completed by the interrupt
4310 * handler.
4311 *
4312 * If ASC_BUSY is returned add the request to the board's per
4313 * target waiting list. This is the first time the request has
4314 * been tried. Add it to the back of the waiting list. It will be
4315 * retried later.
4316 *
4317 * If an error occurred, the request will have been placed on the
4318 * board's 'done' queue and must be completed before returning.
4319 */
4320 scp->scsi_done = done;
4321 switch (asc_execute_scsi_cmnd(scp)) {
4322 case ASC_NOERROR:
4323 break;
4324 case ASC_BUSY:
4325 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4326 break;
4327 case ASC_ERROR:
4328 default:
4329 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4330 /* Interrupts could be enabled here. */
4331 asc_scsi_done_list(done_scp);
4332 break;
4333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004336 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337}
4338
4339/*
4340 * advansys_reset()
4341 *
4342 * Reset the bus associated with the command 'scp'.
4343 *
4344 * This function runs its own thread. Interrupts must be blocked but
4345 * sleeping is allowed and no locking other than for host structures is
4346 * required. Returns SUCCESS or FAILED.
4347 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004348static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004350 struct Scsi_Host *shost;
4351 asc_board_t *boardp;
4352 ASC_DVC_VAR *asc_dvc_varp;
4353 ADV_DVC_VAR *adv_dvc_varp;
4354 ulong flags;
4355 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4356 struct scsi_cmnd *tscp, *new_last_scp;
4357 int status;
4358 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004360 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361
4362#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004363 if (scp->device->host != NULL) {
4364 ASC_STATS(scp->device->host, reset);
4365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366#endif /* ADVANSYS_STATS */
4367
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004368 if ((shost = scp->device->host) == NULL) {
4369 scp->result = HOST_BYTE(DID_ERROR);
4370 return FAILED;
4371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004373 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004375 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4376 boardp->id);
4377 /*
4378 * Check for re-entrancy.
4379 */
4380 spin_lock_irqsave(&boardp->lock, flags);
4381 if (boardp->flags & ASC_HOST_IN_RESET) {
4382 spin_unlock_irqrestore(&boardp->lock, flags);
4383 return FAILED;
4384 }
4385 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004388 if (ASC_NARROW_BOARD(boardp)) {
4389 /*
4390 * Narrow Board
4391 */
4392 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004394 /*
4395 * Reset the chip and SCSI bus.
4396 */
4397 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4398 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004399
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004400 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4401 if (asc_dvc_varp->err_code) {
4402 ASC_PRINT2
4403 ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
4404 boardp->id, asc_dvc_varp->err_code);
4405 ret = FAILED;
4406 } else if (status) {
4407 ASC_PRINT2
4408 ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
4409 boardp->id, status);
4410 } else {
4411 ASC_PRINT1
4412 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4413 boardp->id);
4414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004416 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4417 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004419 } else {
4420 /*
4421 * Wide Board
4422 *
4423 * If the suggest reset bus flags are set, then reset the bus.
4424 * Otherwise only reset the device.
4425 */
4426 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004428 /*
4429 * Reset the target's SCSI bus.
4430 */
4431 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4432 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4433 case ASC_TRUE:
4434 ASC_PRINT1
4435 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4436 boardp->id);
4437 break;
4438 case ASC_FALSE:
4439 default:
4440 ASC_PRINT1
4441 ("advansys_reset: board %d: SCSI bus reset error.\n",
4442 boardp->id);
4443 ret = FAILED;
4444 break;
4445 }
4446 spin_lock_irqsave(&boardp->lock, flags);
4447 (void)AdvISR(adv_dvc_varp);
4448 }
4449 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004451 /*
4452 * Dequeue all board 'done' requests. A pointer to the last request
4453 * is returned in 'last_scp'.
4454 */
4455 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004457 /*
4458 * Dequeue all board 'active' requests for all devices and set
4459 * the request status to DID_RESET. A pointer to the last request
4460 * is returned in 'last_scp'.
4461 */
4462 if (done_scp == NULL) {
4463 done_scp =
4464 asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
4465 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4466 tscp->result = HOST_BYTE(DID_RESET);
4467 }
4468 } else {
4469 /* Append to 'done_scp' at the end with 'last_scp'. */
4470 ASC_ASSERT(last_scp != NULL);
4471 last_scp->host_scribble =
4472 (unsigned char *)asc_dequeue_list(&boardp->active,
4473 &new_last_scp,
4474 ASC_TID_ALL);
4475 if (new_last_scp != NULL) {
4476 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4477 for (tscp = REQPNEXT(last_scp); tscp;
4478 tscp = REQPNEXT(tscp)) {
4479 tscp->result = HOST_BYTE(DID_RESET);
4480 }
4481 last_scp = new_last_scp;
4482 }
4483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004485 /*
4486 * Dequeue all 'waiting' requests and set the request status
4487 * to DID_RESET.
4488 */
4489 if (done_scp == NULL) {
4490 done_scp =
4491 asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
4492 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4493 tscp->result = HOST_BYTE(DID_RESET);
4494 }
4495 } else {
4496 /* Append to 'done_scp' at the end with 'last_scp'. */
4497 ASC_ASSERT(last_scp != NULL);
4498 last_scp->host_scribble =
4499 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4500 &new_last_scp,
4501 ASC_TID_ALL);
4502 if (new_last_scp != NULL) {
4503 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4504 for (tscp = REQPNEXT(last_scp); tscp;
4505 tscp = REQPNEXT(tscp)) {
4506 tscp->result = HOST_BYTE(DID_RESET);
4507 }
4508 last_scp = new_last_scp;
4509 }
4510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004512 /* Save the time of the most recently completed reset. */
4513 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004515 /* Clear reset flag. */
4516 boardp->flags &= ~ASC_HOST_IN_RESET;
4517 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004519 /*
4520 * Complete all the 'done_scp' requests.
4521 */
4522 if (done_scp != NULL) {
4523 asc_scsi_done_list(done_scp);
4524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004526 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004528 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529}
4530
4531/*
4532 * advansys_biosparam()
4533 *
4534 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4535 * support is enabled for a drive.
4536 *
4537 * ip (information pointer) is an int array with the following definition:
4538 * ip[0]: heads
4539 * ip[1]: sectors
4540 * ip[2]: cylinders
4541 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004542static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004544 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004546 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004548 ASC_DBG(1, "advansys_biosparam: begin\n");
4549 ASC_STATS(sdev->host, biosparam);
4550 boardp = ASC_BOARDP(sdev->host);
4551 if (ASC_NARROW_BOARD(boardp)) {
4552 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4553 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4554 ip[0] = 255;
4555 ip[1] = 63;
4556 } else {
4557 ip[0] = 64;
4558 ip[1] = 32;
4559 }
4560 } else {
4561 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4562 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4563 ip[0] = 255;
4564 ip[1] = 63;
4565 } else {
4566 ip[0] = 64;
4567 ip[1] = 32;
4568 }
4569 }
4570 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4571 ASC_DBG(1, "advansys_biosparam: end\n");
4572 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573}
4574
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004575static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004576 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004578 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004580 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004581 .info = advansys_info,
4582 .queuecommand = advansys_queuecommand,
4583 .eh_bus_reset_handler = advansys_reset,
4584 .bios_param = advansys_biosparam,
4585 .slave_configure = advansys_slave_configure,
4586 /*
4587 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004588 * must be set. The flag will be cleared in advansys_board_found
4589 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004590 */
4591 .unchecked_isa_dma = 1,
4592 /*
4593 * All adapters controlled by this driver are capable of large
4594 * scatter-gather lists. According to the mid-level SCSI documentation
4595 * this obviates any performance gain provided by setting
4596 * 'use_clustering'. But empirically while CPU utilization is increased
4597 * by enabling clustering, I/O throughput increases as well.
4598 */
4599 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602/*
4603 * --- Miscellaneous Driver Functions
4604 */
4605
4606/*
4607 * First-level interrupt handler.
4608 *
4609 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4610 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4611 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4612 * to the AdvanSys driver which is for a device sharing an interrupt with
4613 * an AdvanSys adapter.
4614 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004615static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004617 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004618 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4619 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004620 struct Scsi_Host *shost = dev_id;
4621 asc_board_t *boardp = ASC_BOARDP(shost);
4622 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004624 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
4625 spin_lock_irqsave(&boardp->lock, flags);
4626 if (ASC_NARROW_BOARD(boardp)) {
4627 /*
4628 * Narrow Board
4629 */
4630 if (AscIsIntPending(shost->io_port)) {
4631 result = IRQ_HANDLED;
4632 ASC_STATS(shost, interrupt);
4633 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
4634 AscISR(&boardp->dvc_var.asc_dvc_var);
4635 }
4636 } else {
4637 /*
4638 * Wide Board
4639 */
4640 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4641 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4642 result = IRQ_HANDLED;
4643 ASC_STATS(shost, interrupt);
4644 }
4645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004647 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004648 * Start waiting requests and create a list of completed requests.
4649 *
4650 * If a reset request is being performed for the board, the reset
4651 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004652 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004653 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4654 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
4655 "last_scp 0x%p\n", done_scp, last_scp);
4656
4657 /* Start any waiting commands for the board. */
4658 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4659 ASC_DBG(1, "advansys_interrupt: before "
4660 "asc_execute_queue()\n");
4661 asc_execute_queue(&boardp->waiting);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004664 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004665 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004666 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004667 * 'done_scp' will always be NULL on the first iteration of
4668 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004669 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004670 if (done_scp == NULL) {
4671 done_scp = asc_dequeue_list(&boardp->done,
4672 &last_scp, ASC_TID_ALL);
4673 } else {
4674 ASC_ASSERT(last_scp != NULL);
4675 last_scp->host_scribble =
4676 (unsigned char *)asc_dequeue_list(&boardp->
4677 done,
4678 &new_last_scp,
4679 ASC_TID_ALL);
4680 if (new_last_scp != NULL) {
4681 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4682 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004683 }
4684 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004685 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004686 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004688 /*
4689 * If interrupts were enabled on entry, then they
4690 * are now enabled here.
4691 *
4692 * Complete all requests on the done list.
4693 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004695 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004697 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004698 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699}
4700
4701/*
4702 * Set the number of commands to queue per device for the
4703 * specified host adapter.
4704 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004705static int advansys_slave_configure(struct scsi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004707 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004709 boardp = ASC_BOARDP(device->host);
4710 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
4711 /*
4712 * Save a pointer to the device and set its initial/maximum
4713 * queue depth. Only save the pointer for a lun0 dev though.
4714 */
4715 if (device->lun == 0)
4716 boardp->device[device->id] = device;
4717 if (device->tagged_supported) {
4718 if (ASC_NARROW_BOARD(boardp)) {
4719 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4720 boardp->dvc_var.asc_dvc_var.
4721 max_dvc_qng[device->id]);
4722 } else {
4723 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4724 boardp->dvc_var.adv_dvc_var.
4725 max_dvc_qng);
4726 }
4727 } else {
4728 scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
4729 }
4730 ASC_DBG4(1,
4731 "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
4732 (ulong)device, (ulong)boardp, device->id, device->queue_depth);
4733 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734}
4735
4736/*
4737 * Complete all requests on the singly linked list pointed
4738 * to by 'scp'.
4739 *
4740 * Interrupts can be enabled on entry.
4741 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004742static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004744 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004746 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4747 while (scp != NULL) {
4748 asc_board_t *boardp;
4749 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004751 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4752 tscp = REQPNEXT(scp);
4753 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004755 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004757 if (ASC_NARROW_BOARD(boardp))
4758 dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
4759 else
4760 dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004762 if (scp->use_sg)
4763 dma_unmap_sg(dev,
4764 (struct scatterlist *)scp->request_buffer,
4765 scp->use_sg, scp->sc_data_direction);
4766 else if (scp->request_bufflen)
4767 dma_unmap_single(dev, scp->SCp.dma_handle,
4768 scp->request_bufflen,
4769 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004771 ASC_STATS(scp->device->host, done);
4772 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004774 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004776 scp = tscp;
4777 }
4778 ASC_DBG(2, "asc_scsi_done_list: done\n");
4779 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780}
4781
4782/*
4783 * Execute a single 'Scsi_Cmnd'.
4784 *
4785 * The function 'done' is called when the request has been completed.
4786 *
4787 * Scsi_Cmnd:
4788 *
4789 * host - board controlling device
4790 * device - device to send command
4791 * target - target of device
4792 * lun - lun of device
4793 * cmd_len - length of SCSI CDB
4794 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4795 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4796 *
4797 * if (use_sg == 0) {
4798 * request_buffer - buffer address for request
4799 * request_bufflen - length of request buffer
4800 * } else {
4801 * request_buffer - pointer to scatterlist structure
4802 * }
4803 *
4804 * sense_buffer - sense command buffer
4805 *
4806 * result (4 bytes of an int):
4807 * Byte Meaning
4808 * 0 SCSI Status Byte Code
4809 * 1 SCSI One Byte Message Code
4810 * 2 Host Error Code
4811 * 3 Mid-Level Error Code
4812 *
4813 * host driver fields:
4814 * SCp - Scsi_Pointer used for command processing status
4815 * scsi_done - used to save caller's done function
4816 * host_scribble - used for pointer to another struct scsi_cmnd
4817 *
4818 * If this function returns ASC_NOERROR the request has been enqueued
4819 * on the board's 'active' queue and will be completed from the
4820 * interrupt handler.
4821 *
4822 * If this function returns ASC_NOERROR the request has been enqueued
4823 * on the board's 'done' queue and must be completed by the caller.
4824 *
4825 * If ASC_BUSY is returned the request will be enqueued by the
4826 * caller on the target's waiting queue and re-tried later.
4827 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004828static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004830 asc_board_t *boardp;
4831 ASC_DVC_VAR *asc_dvc_varp;
4832 ADV_DVC_VAR *adv_dvc_varp;
4833 ADV_SCSI_REQ_Q *adv_scsiqp;
4834 struct scsi_device *device;
4835 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004837 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4838 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004840 boardp = ASC_BOARDP(scp->device->host);
4841 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004843 if (ASC_NARROW_BOARD(boardp)) {
4844 /*
4845 * Build and execute Narrow Board request.
4846 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004848 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004850 /*
4851 * Build Asc Library request structure using the
4852 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4853 *
4854 * If an error is returned, then the request has been
4855 * queued on the board done queue. It will be completed
4856 * by the caller.
4857 *
4858 * asc_build_req() can not return ASC_BUSY.
4859 */
4860 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4861 ASC_STATS(scp->device->host, build_error);
4862 return ASC_ERROR;
4863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004865 /*
4866 * Execute the command. If there is no error, add the command
4867 * to the active queue.
4868 */
4869 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4870 case ASC_NOERROR:
4871 ASC_STATS(scp->device->host, exe_noerror);
4872 /*
4873 * Increment monotonically increasing per device successful
4874 * request counter. Wrapping doesn't matter.
4875 */
4876 boardp->reqcnt[scp->device->id]++;
4877 asc_enqueue(&boardp->active, scp, ASC_BACK);
4878 ASC_DBG(1,
4879 "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
4880 break;
4881 case ASC_BUSY:
4882 /*
4883 * Caller will enqueue request on the target's waiting queue
4884 * and retry later.
4885 */
4886 ASC_STATS(scp->device->host, exe_busy);
4887 break;
4888 case ASC_ERROR:
4889 ASC_PRINT2
4890 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4891 boardp->id, asc_dvc_varp->err_code);
4892 ASC_STATS(scp->device->host, exe_error);
4893 scp->result = HOST_BYTE(DID_ERROR);
4894 asc_enqueue(&boardp->done, scp, ASC_BACK);
4895 break;
4896 default:
4897 ASC_PRINT2
4898 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
4899 boardp->id, asc_dvc_varp->err_code);
4900 ASC_STATS(scp->device->host, exe_unknown);
4901 scp->result = HOST_BYTE(DID_ERROR);
4902 asc_enqueue(&boardp->done, scp, ASC_BACK);
4903 break;
4904 }
4905 } else {
4906 /*
4907 * Build and execute Wide Board request.
4908 */
4909 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004911 /*
4912 * Build and get a pointer to an Adv Library request structure.
4913 *
4914 * If the request is successfully built then send it below,
4915 * otherwise return with an error.
4916 */
4917 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4918 case ASC_NOERROR:
4919 ASC_DBG(3,
4920 "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
4921 break;
4922 case ASC_BUSY:
4923 ASC_DBG(1,
4924 "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
4925 /*
4926 * If busy is returned the request has not been enqueued.
4927 * It will be enqueued by the caller on the target's waiting
4928 * queue and retried later.
4929 *
4930 * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
4931 * count wide board busy conditions. They are updated in
4932 * adv_build_req and adv_get_sglist, respectively.
4933 */
4934 return ASC_BUSY;
4935 case ASC_ERROR:
4936 /*
4937 * If an error is returned, then the request has been
4938 * queued on the board done queue. It will be completed
4939 * by the caller.
4940 */
4941 default:
4942 ASC_DBG(1,
4943 "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
4944 ASC_STATS(scp->device->host, build_error);
4945 return ASC_ERROR;
4946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004948 /*
4949 * Execute the command. If there is no error, add the command
4950 * to the active queue.
4951 */
4952 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
4953 case ASC_NOERROR:
4954 ASC_STATS(scp->device->host, exe_noerror);
4955 /*
4956 * Increment monotonically increasing per device successful
4957 * request counter. Wrapping doesn't matter.
4958 */
4959 boardp->reqcnt[scp->device->id]++;
4960 asc_enqueue(&boardp->active, scp, ASC_BACK);
4961 ASC_DBG(1,
4962 "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
4963 break;
4964 case ASC_BUSY:
4965 /*
4966 * Caller will enqueue request on the target's waiting queue
4967 * and retry later.
4968 */
4969 ASC_STATS(scp->device->host, exe_busy);
4970 break;
4971 case ASC_ERROR:
4972 ASC_PRINT2
4973 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4974 boardp->id, adv_dvc_varp->err_code);
4975 ASC_STATS(scp->device->host, exe_error);
4976 scp->result = HOST_BYTE(DID_ERROR);
4977 asc_enqueue(&boardp->done, scp, ASC_BACK);
4978 break;
4979 default:
4980 ASC_PRINT2
4981 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
4982 boardp->id, adv_dvc_varp->err_code);
4983 ASC_STATS(scp->device->host, exe_unknown);
4984 scp->result = HOST_BYTE(DID_ERROR);
4985 asc_enqueue(&boardp->done, scp, ASC_BACK);
4986 break;
4987 }
4988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004990 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
4991 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992}
4993
4994/*
4995 * Build a request structure for the Asc Library (Narrow Board).
4996 *
4997 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
4998 * used to build the request.
4999 *
5000 * If an error occurs, then queue the request on the board done
5001 * queue and return ASC_ERROR.
5002 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005003static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005005 struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005007 /*
5008 * Mutually exclusive access is required to 'asc_scsi_q' and
5009 * 'asc_sg_head' until after the request is started.
5010 */
5011 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005013 /*
5014 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
5015 */
5016 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005018 /*
5019 * Build the ASC_SCSI_Q request.
5020 *
5021 * For narrow boards a CDB length maximum of 12 bytes
5022 * is supported.
5023 */
5024 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
5025 ASC_PRINT3
5026 ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n",
5027 boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
5028 scp->result = HOST_BYTE(DID_ERROR);
5029 asc_enqueue(&boardp->done, scp, ASC_BACK);
5030 return ASC_ERROR;
5031 }
5032 asc_scsi_q.cdbptr = &scp->cmnd[0];
5033 asc_scsi_q.q2.cdb_len = scp->cmd_len;
5034 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
5035 asc_scsi_q.q1.target_lun = scp->device->lun;
5036 asc_scsi_q.q2.target_ix =
5037 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
5038 asc_scsi_q.q1.sense_addr =
5039 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5040 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005042 /*
5043 * If there are any outstanding requests for the current target,
5044 * then every 255th request send an ORDERED request. This heuristic
5045 * tries to retain the benefit of request sorting while preventing
5046 * request starvation. 255 is the max number of tags or pending commands
5047 * a device may have outstanding.
5048 *
5049 * The request count is incremented below for every successfully
5050 * started request.
5051 *
5052 */
5053 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
5054 (boardp->reqcnt[scp->device->id] % 255) == 0) {
5055 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
5056 } else {
5057 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
5058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005060 /*
5061 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
5062 * buffer command.
5063 */
5064 if (scp->use_sg == 0) {
5065 /*
5066 * CDB request of single contiguous buffer.
5067 */
5068 ASC_STATS(scp->device->host, cont_cnt);
5069 scp->SCp.dma_handle = scp->request_bufflen ?
5070 dma_map_single(dev, scp->request_buffer,
5071 scp->request_bufflen,
5072 scp->sc_data_direction) : 0;
5073 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
5074 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
5075 ASC_STATS_ADD(scp->device->host, cont_xfer,
5076 ASC_CEILING(scp->request_bufflen, 512));
5077 asc_scsi_q.q1.sg_queue_cnt = 0;
5078 asc_scsi_q.sg_head = NULL;
5079 } else {
5080 /*
5081 * CDB scatter-gather request list.
5082 */
5083 int sgcnt;
5084 int use_sg;
5085 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005087 slp = (struct scatterlist *)scp->request_buffer;
5088 use_sg =
5089 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005091 if (use_sg > scp->device->host->sg_tablesize) {
5092 ASC_PRINT3
5093 ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
5094 boardp->id, use_sg,
5095 scp->device->host->sg_tablesize);
5096 dma_unmap_sg(dev, slp, scp->use_sg,
5097 scp->sc_data_direction);
5098 scp->result = HOST_BYTE(DID_ERROR);
5099 asc_enqueue(&boardp->done, scp, ASC_BACK);
5100 return ASC_ERROR;
5101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005103 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005105 /*
5106 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
5107 * structure to point to it.
5108 */
5109 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005111 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5112 asc_scsi_q.sg_head = &asc_sg_head;
5113 asc_scsi_q.q1.data_cnt = 0;
5114 asc_scsi_q.q1.data_addr = 0;
5115 /* This is a byte value, otherwise it would need to be swapped. */
5116 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5117 ASC_STATS_ADD(scp->device->host, sg_elem,
5118 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005120 /*
5121 * Convert scatter-gather list into ASC_SG_HEAD list.
5122 */
5123 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5124 asc_sg_head.sg_list[sgcnt].addr =
5125 cpu_to_le32(sg_dma_address(slp));
5126 asc_sg_head.sg_list[sgcnt].bytes =
5127 cpu_to_le32(sg_dma_len(slp));
5128 ASC_STATS_ADD(scp->device->host, sg_xfer,
5129 ASC_CEILING(sg_dma_len(slp), 512));
5130 }
5131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005133 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5134 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005136 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137}
5138
5139/*
5140 * Build a request structure for the Adv Library (Wide Board).
5141 *
5142 * If an adv_req_t can not be allocated to issue the request,
5143 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5144 *
5145 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5146 * microcode for DMA addresses or math operations are byte swapped
5147 * to little-endian order.
5148 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005149static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005151 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005153 adv_req_t *reqp;
5154 ADV_SCSI_REQ_Q *scsiqp;
5155 int i;
5156 int ret;
5157 struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005159 /*
5160 * Allocate an adv_req_t structure from the board to execute
5161 * the command.
5162 */
5163 if (boardp->adv_reqp == NULL) {
5164 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5165 ASC_STATS(scp->device->host, adv_build_noreq);
5166 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005168 reqp = boardp->adv_reqp;
5169 boardp->adv_reqp = reqp->next_reqp;
5170 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005173 /*
5174 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5175 */
5176 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005178 /*
5179 * Initialize the structure.
5180 */
5181 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005183 /*
5184 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5185 */
5186 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005188 /*
5189 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5190 */
5191 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005193 /*
5194 * Build the ADV_SCSI_REQ_Q request.
5195 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005197 /*
5198 * Set CDB length and copy it to the request structure.
5199 * For wide boards a CDB length maximum of 16 bytes
5200 * is supported.
5201 */
5202 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5203 ASC_PRINT3
5204 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5205 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5206 scp->result = HOST_BYTE(DID_ERROR);
5207 asc_enqueue(&boardp->done, scp, ASC_BACK);
5208 return ASC_ERROR;
5209 }
5210 scsiqp->cdb_len = scp->cmd_len;
5211 /* Copy first 12 CDB bytes to cdb[]. */
5212 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5213 scsiqp->cdb[i] = scp->cmnd[i];
5214 }
5215 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5216 for (; i < scp->cmd_len; i++) {
5217 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005220 scsiqp->target_id = scp->device->id;
5221 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005223 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5224 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005226 /*
5227 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5228 * buffer command.
5229 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005231 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5232 scsiqp->vdata_addr = scp->request_buffer;
5233 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5234
5235 if (scp->use_sg == 0) {
5236 /*
5237 * CDB request of single contiguous buffer.
5238 */
5239 reqp->sgblkp = NULL;
5240 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5241 if (scp->request_bufflen) {
5242 scsiqp->vdata_addr = scp->request_buffer;
5243 scp->SCp.dma_handle =
5244 dma_map_single(dev, scp->request_buffer,
5245 scp->request_bufflen,
5246 scp->sc_data_direction);
5247 } else {
5248 scsiqp->vdata_addr = NULL;
5249 scp->SCp.dma_handle = 0;
5250 }
5251 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5252 scsiqp->sg_list_ptr = NULL;
5253 scsiqp->sg_real_addr = 0;
5254 ASC_STATS(scp->device->host, cont_cnt);
5255 ASC_STATS_ADD(scp->device->host, cont_xfer,
5256 ASC_CEILING(scp->request_bufflen, 512));
5257 } else {
5258 /*
5259 * CDB scatter-gather request list.
5260 */
5261 struct scatterlist *slp;
5262 int use_sg;
5263
5264 slp = (struct scatterlist *)scp->request_buffer;
5265 use_sg =
5266 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
5267
5268 if (use_sg > ADV_MAX_SG_LIST) {
5269 ASC_PRINT3
5270 ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
5271 boardp->id, use_sg,
5272 scp->device->host->sg_tablesize);
5273 dma_unmap_sg(dev, slp, scp->use_sg,
5274 scp->sc_data_direction);
5275 scp->result = HOST_BYTE(DID_ERROR);
5276 asc_enqueue(&boardp->done, scp, ASC_BACK);
5277
5278 /*
5279 * Free the 'adv_req_t' structure by adding it back to the
5280 * board free list.
5281 */
5282 reqp->next_reqp = boardp->adv_reqp;
5283 boardp->adv_reqp = reqp;
5284
5285 return ASC_ERROR;
5286 }
5287
5288 if ((ret =
5289 adv_get_sglist(boardp, reqp, scp,
5290 use_sg)) != ADV_SUCCESS) {
5291 /*
5292 * Free the adv_req_t structure by adding it back to the
5293 * board free list.
5294 */
5295 reqp->next_reqp = boardp->adv_reqp;
5296 boardp->adv_reqp = reqp;
5297
5298 return ret;
5299 }
5300
5301 ASC_STATS(scp->device->host, sg_cnt);
5302 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5303 }
5304
5305 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5306 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5307
5308 *adv_scsiqpp = scsiqp;
5309
5310 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311}
5312
5313/*
5314 * Build scatter-gather list for Adv Library (Wide Board).
5315 *
5316 * Additional ADV_SG_BLOCK structures will need to be allocated
5317 * if the total number of scatter-gather elements exceeds
5318 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5319 * assumed to be physically contiguous.
5320 *
5321 * Return:
5322 * ADV_SUCCESS(1) - SG List successfully created
5323 * ADV_ERROR(-1) - SG List creation failed
5324 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005325static int
5326adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5327 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005329 adv_sgblk_t *sgblkp;
5330 ADV_SCSI_REQ_Q *scsiqp;
5331 struct scatterlist *slp;
5332 int sg_elem_cnt;
5333 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5334 ADV_PADDR sg_block_paddr;
5335 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005337 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5338 slp = (struct scatterlist *)scp->request_buffer;
5339 sg_elem_cnt = use_sg;
5340 prev_sg_block = NULL;
5341 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005343 do {
5344 /*
5345 * Allocate a 'adv_sgblk_t' structure from the board free
5346 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5347 * (15) scatter-gather elements.
5348 */
5349 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5350 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5351 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005353 /*
5354 * Allocation failed. Free 'adv_sgblk_t' structures already
5355 * allocated for the request.
5356 */
5357 while ((sgblkp = reqp->sgblkp) != NULL) {
5358 /* Remove 'sgblkp' from the request list. */
5359 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005361 /* Add 'sgblkp' to the board free list. */
5362 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5363 boardp->adv_sgblkp = sgblkp;
5364 }
5365 return ASC_BUSY;
5366 } else {
5367 /* Complete 'adv_sgblk_t' board allocation. */
5368 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5369 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005371 /*
5372 * Get 8 byte aligned virtual and physical addresses for
5373 * the allocated ADV_SG_BLOCK structure.
5374 */
5375 sg_block =
5376 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5377 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005379 /*
5380 * Check if this is the first 'adv_sgblk_t' for the request.
5381 */
5382 if (reqp->sgblkp == NULL) {
5383 /* Request's first scatter-gather block. */
5384 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005386 /*
5387 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5388 * address pointers.
5389 */
5390 scsiqp->sg_list_ptr = sg_block;
5391 scsiqp->sg_real_addr =
5392 cpu_to_le32(sg_block_paddr);
5393 } else {
5394 /* Request's second or later scatter-gather block. */
5395 sgblkp->next_sgblkp = reqp->sgblkp;
5396 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005398 /*
5399 * Point the previous ADV_SG_BLOCK structure to
5400 * the newly allocated ADV_SG_BLOCK structure.
5401 */
5402 ASC_ASSERT(prev_sg_block != NULL);
5403 prev_sg_block->sg_ptr =
5404 cpu_to_le32(sg_block_paddr);
5405 }
5406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005408 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5409 sg_block->sg_list[i].sg_addr =
5410 cpu_to_le32(sg_dma_address(slp));
5411 sg_block->sg_list[i].sg_count =
5412 cpu_to_le32(sg_dma_len(slp));
5413 ASC_STATS_ADD(scp->device->host, sg_xfer,
5414 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005416 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5417 sg_block->sg_cnt = i + 1;
5418 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5419 return ADV_SUCCESS;
5420 }
5421 slp++;
5422 }
5423 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5424 prev_sg_block = sg_block;
5425 }
5426 while (1);
5427 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428}
5429
5430/*
5431 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5432 *
5433 * Interrupt callback function for the Narrow SCSI Asc Library.
5434 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005435static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005437 asc_board_t *boardp;
5438 struct scsi_cmnd *scp;
5439 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005441 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5442 (ulong)asc_dvc_varp, (ulong)qdonep);
5443 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005444
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005445 /*
5446 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5447 * command that has been completed.
5448 */
5449 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5450 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005452 if (scp == NULL) {
5453 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5454 return;
5455 }
5456 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005458 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005459 ASC_STATS(shost, callback);
5460 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005462 /*
5463 * If the request isn't found on the active queue, it may
5464 * have been removed to handle a reset request.
5465 * Display a message and return.
5466 */
5467 boardp = ASC_BOARDP(shost);
5468 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5469 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5470 ASC_PRINT2
5471 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5472 boardp->id, (ulong)scp);
5473 return;
5474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005476 /*
5477 * 'qdonep' contains the command's ending status.
5478 */
5479 switch (qdonep->d3.done_stat) {
5480 case QD_NO_ERROR:
5481 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5482 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005484 /*
5485 * If an INQUIRY command completed successfully, then call
5486 * the AscInquiryHandling() function to set-up the device.
5487 */
5488 if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
5489 (scp->request_bufflen - qdonep->remain_bytes) >= 8) {
5490 AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
5491 (ASC_SCSI_INQUIRY *)scp->
5492 request_buffer);
5493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005495 /*
5496 * Check for an underrun condition.
5497 *
5498 * If there was no error and an underrun condition, then
5499 * then return the number of underrun bytes.
5500 */
5501 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5502 qdonep->remain_bytes <= scp->request_bufflen) {
5503 ASC_DBG1(1,
5504 "asc_isr_callback: underrun condition %u bytes\n",
5505 (unsigned)qdonep->remain_bytes);
5506 scp->resid = qdonep->remain_bytes;
5507 }
5508 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005510 case QD_WITH_ERROR:
5511 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5512 switch (qdonep->d3.host_stat) {
5513 case QHSTA_NO_ERROR:
5514 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5515 ASC_DBG(2,
5516 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5517 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5518 sizeof(scp->sense_buffer));
5519 /*
5520 * Note: The 'status_byte()' macro used by target drivers
5521 * defined in scsi.h shifts the status byte returned by
5522 * host drivers right by 1 bit. This is why target drivers
5523 * also use right shifted status byte definitions. For
5524 * instance target drivers use CHECK_CONDITION, defined to
5525 * 0x1, instead of the SCSI defined check condition value
5526 * of 0x2. Host drivers are supposed to return the status
5527 * byte as it is defined by SCSI.
5528 */
5529 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5530 STATUS_BYTE(qdonep->d3.scsi_stat);
5531 } else {
5532 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5533 }
5534 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005536 default:
5537 /* QHSTA error occurred */
5538 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5539 qdonep->d3.host_stat);
5540 scp->result = HOST_BYTE(DID_BAD_TARGET);
5541 break;
5542 }
5543 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005545 case QD_ABORTED_BY_HOST:
5546 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5547 scp->result =
5548 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5549 scsi_msg) |
5550 STATUS_BYTE(qdonep->d3.scsi_stat);
5551 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005553 default:
5554 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5555 qdonep->d3.done_stat);
5556 scp->result =
5557 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5558 scsi_msg) |
5559 STATUS_BYTE(qdonep->d3.scsi_stat);
5560 break;
5561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005563 /*
5564 * If the 'init_tidmask' bit isn't already set for the target and the
5565 * current request finished normally, then set the bit for the target
5566 * to indicate that a device is present.
5567 */
5568 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5569 qdonep->d3.done_stat == QD_NO_ERROR &&
5570 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5571 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005574 /*
5575 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5576 * function, add the command to the end of the board's done queue.
5577 * The done function for the command will be called from
5578 * advansys_interrupt().
5579 */
5580 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005582 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583}
5584
5585/*
5586 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5587 *
5588 * Callback function for the Wide SCSI Adv Library.
5589 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005590static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005592 asc_board_t *boardp;
5593 adv_req_t *reqp;
5594 adv_sgblk_t *sgblkp;
5595 struct scsi_cmnd *scp;
5596 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005597 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005599 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5600 (ulong)adv_dvc_varp, (ulong)scsiqp);
5601 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005603 /*
5604 * Get the adv_req_t structure for the command that has been
5605 * completed. The adv_req_t structure actually contains the
5606 * completed ADV_SCSI_REQ_Q structure.
5607 */
5608 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5609 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5610 if (reqp == NULL) {
5611 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5612 return;
5613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005615 /*
5616 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5617 * command that has been completed.
5618 *
5619 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5620 * if any, are dropped, because a board structure pointer can not be
5621 * determined.
5622 */
5623 scp = reqp->cmndp;
5624 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5625 if (scp == NULL) {
5626 ASC_PRINT
5627 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5628 return;
5629 }
5630 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005632 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005633 ASC_STATS(shost, callback);
5634 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005636 /*
5637 * If the request isn't found on the active queue, it may have been
5638 * removed to handle a reset request. Display a message and return.
5639 *
5640 * Note: Because the structure may still be in use don't attempt
5641 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5642 */
5643 boardp = ASC_BOARDP(shost);
5644 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5645 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5646 ASC_PRINT2
5647 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5648 boardp->id, (ulong)scp);
5649 return;
5650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005652 /*
5653 * 'done_status' contains the command's ending status.
5654 */
5655 switch (scsiqp->done_status) {
5656 case QD_NO_ERROR:
5657 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5658 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005660 /*
5661 * Check for an underrun condition.
5662 *
5663 * If there was no error and an underrun condition, then
5664 * then return the number of underrun bytes.
5665 */
5666 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5667 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5668 resid_cnt <= scp->request_bufflen) {
5669 ASC_DBG1(1,
5670 "adv_isr_callback: underrun condition %lu bytes\n",
5671 (ulong)resid_cnt);
5672 scp->resid = resid_cnt;
5673 }
5674 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005676 case QD_WITH_ERROR:
5677 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5678 switch (scsiqp->host_status) {
5679 case QHSTA_NO_ERROR:
5680 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5681 ASC_DBG(2,
5682 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5683 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5684 sizeof(scp->sense_buffer));
5685 /*
5686 * Note: The 'status_byte()' macro used by target drivers
5687 * defined in scsi.h shifts the status byte returned by
5688 * host drivers right by 1 bit. This is why target drivers
5689 * also use right shifted status byte definitions. For
5690 * instance target drivers use CHECK_CONDITION, defined to
5691 * 0x1, instead of the SCSI defined check condition value
5692 * of 0x2. Host drivers are supposed to return the status
5693 * byte as it is defined by SCSI.
5694 */
5695 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5696 STATUS_BYTE(scsiqp->scsi_status);
5697 } else {
5698 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5699 }
5700 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005702 default:
5703 /* Some other QHSTA error occurred. */
5704 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5705 scsiqp->host_status);
5706 scp->result = HOST_BYTE(DID_BAD_TARGET);
5707 break;
5708 }
5709 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005711 case QD_ABORTED_BY_HOST:
5712 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5713 scp->result =
5714 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5715 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005717 default:
5718 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5719 scsiqp->done_status);
5720 scp->result =
5721 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5722 break;
5723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005725 /*
5726 * If the 'init_tidmask' bit isn't already set for the target and the
5727 * current request finished normally, then set the bit for the target
5728 * to indicate that a device is present.
5729 */
5730 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5731 scsiqp->done_status == QD_NO_ERROR &&
5732 scsiqp->host_status == QHSTA_NO_ERROR) {
5733 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005736 /*
5737 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5738 * function, add the command to the end of the board's done queue.
5739 * The done function for the command will be called from
5740 * advansys_interrupt().
5741 */
5742 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005744 /*
5745 * Free all 'adv_sgblk_t' structures allocated for the request.
5746 */
5747 while ((sgblkp = reqp->sgblkp) != NULL) {
5748 /* Remove 'sgblkp' from the request list. */
5749 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005751 /* Add 'sgblkp' to the board free list. */
5752 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5753 boardp->adv_sgblkp = sgblkp;
5754 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005756 /*
5757 * Free the adv_req_t structure used with the command by adding
5758 * it back to the board free list.
5759 */
5760 reqp->next_reqp = boardp->adv_reqp;
5761 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005763 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005765 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766}
5767
5768/*
5769 * adv_async_callback() - Adv Library asynchronous event callback function.
5770 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005771static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005773 switch (code) {
5774 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5775 /*
5776 * The firmware detected a SCSI Bus reset.
5777 */
5778 ASC_DBG(0,
5779 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5780 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005782 case ADV_ASYNC_RDMA_FAILURE:
5783 /*
5784 * Handle RDMA failure by resetting the SCSI Bus and
5785 * possibly the chip if it is unresponsive. Log the error
5786 * with a unique code.
5787 */
5788 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5789 AdvResetChipAndSB(adv_dvc_varp);
5790 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005792 case ADV_HOST_SCSI_BUS_RESET:
5793 /*
5794 * Host generated SCSI bus reset occurred.
5795 */
5796 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5797 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005798
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005799 default:
5800 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5801 break;
5802 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803}
5804
5805/*
5806 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5807 * to indicate a command is queued for the device.
5808 *
5809 * 'flag' may be either ASC_FRONT or ASC_BACK.
5810 *
5811 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5812 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005813static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005815 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005816
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005817 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5818 (ulong)ascq, (ulong)reqp, flag);
5819 ASC_ASSERT(reqp != NULL);
5820 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5821 tid = REQPTID(reqp);
5822 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5823 if (flag == ASC_FRONT) {
5824 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5825 ascq->q_first[tid] = reqp;
5826 /* If the queue was empty, set the last pointer. */
5827 if (ascq->q_last[tid] == NULL) {
5828 ascq->q_last[tid] = reqp;
5829 }
5830 } else { /* ASC_BACK */
5831 if (ascq->q_last[tid] != NULL) {
5832 ascq->q_last[tid]->host_scribble =
5833 (unsigned char *)reqp;
5834 }
5835 ascq->q_last[tid] = reqp;
5836 reqp->host_scribble = NULL;
5837 /* If the queue was empty, set the first pointer. */
5838 if (ascq->q_first[tid] == NULL) {
5839 ascq->q_first[tid] = reqp;
5840 }
5841 }
5842 /* The queue has at least one entry, set its bit. */
5843 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005845 /* Maintain request queue statistics. */
5846 ascq->q_tot_cnt[tid]++;
5847 ascq->q_cur_cnt[tid]++;
5848 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5849 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5850 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5851 tid, ascq->q_max_cnt[tid]);
5852 }
5853 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005855 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5856 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857}
5858
5859/*
5860 * Return first queued 'REQP' on the specified queue for
5861 * the specified target device. Clear the 'tidmask' bit for
5862 * the device if no more commands are left queued for it.
5863 *
5864 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5865 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005866static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005868 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005870 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5871 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5872 if ((reqp = ascq->q_first[tid]) != NULL) {
5873 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5874 ascq->q_first[tid] = REQPNEXT(reqp);
5875 /* If the queue is empty, clear its bit and the last pointer. */
5876 if (ascq->q_first[tid] == NULL) {
5877 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5878 ASC_ASSERT(ascq->q_last[tid] == reqp);
5879 ascq->q_last[tid] = NULL;
5880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005882 /* Maintain request queue statistics. */
5883 ascq->q_cur_cnt[tid]--;
5884 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
5885 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005887 }
5888 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
5889 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890}
5891
5892/*
5893 * Return a pointer to a singly linked list of all the requests queued
5894 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
5895 *
5896 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
5897 * the last request returned in the singly linked list.
5898 *
5899 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
5900 * then all queued requests are concatenated into one list and
5901 * returned.
5902 *
5903 * Note: If 'lastpp' is used to append a new list to the end of
5904 * an old list, only change the old list last pointer if '*lastpp'
5905 * (or the function return value) is not NULL, i.e. use a temporary
5906 * variable for 'lastpp' and check its value after the function return
5907 * before assigning it to the list last pointer.
5908 *
5909 * Unfortunately collecting queuing time statistics adds overhead to
5910 * the function that isn't inherent to the function's algorithm.
5911 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005912static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005914 REQP firstp, lastp;
5915 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005917 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5918 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005920 /*
5921 * If 'tid' is not ASC_TID_ALL, return requests only for
5922 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
5923 * requests for all tids.
5924 */
5925 if (tid != ASC_TID_ALL) {
5926 /* Return all requests for the specified 'tid'. */
5927 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
5928 /* List is empty; Set first and last return pointers to NULL. */
5929 firstp = lastp = NULL;
5930 } else {
5931 firstp = ascq->q_first[tid];
5932 lastp = ascq->q_last[tid];
5933 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
5934 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005936 {
5937 REQP reqp;
5938 ascq->q_cur_cnt[tid] = 0;
5939 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5940 REQTIMESTAT("asc_dequeue_list", ascq,
5941 reqp, tid);
5942 }
5943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005945 }
5946 } else {
5947 /* Return all requests for all tids. */
5948 firstp = lastp = NULL;
5949 for (i = 0; i <= ADV_MAX_TID; i++) {
5950 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
5951 if (firstp == NULL) {
5952 firstp = ascq->q_first[i];
5953 lastp = ascq->q_last[i];
5954 } else {
5955 ASC_ASSERT(lastp != NULL);
5956 lastp->host_scribble =
5957 (unsigned char *)ascq->q_first[i];
5958 lastp = ascq->q_last[i];
5959 }
5960 ascq->q_first[i] = ascq->q_last[i] = NULL;
5961 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005963 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005965 }
5966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005968 {
5969 REQP reqp;
5970 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5971 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
5972 reqp->device->id);
5973 }
5974 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005976 }
5977 if (lastpp) {
5978 *lastpp = lastp;
5979 }
5980 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
5981 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982}
5983
5984/*
5985 * Remove the specified 'REQP' from the specified queue for
5986 * the specified target device. Clear the 'tidmask' bit for the
5987 * device if no more commands are left queued for it.
5988 *
5989 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
5990 *
5991 * Return ASC_TRUE if the command was found and removed,
5992 * otherwise return ASC_FALSE.
5993 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005994static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005996 REQP currp, prevp;
5997 int tid;
5998 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006000 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
6001 (ulong)ascq, (ulong)reqp);
6002 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006004 tid = REQPTID(reqp);
6005 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006007 /*
6008 * Handle the common case of 'reqp' being the first
6009 * entry on the queue.
6010 */
6011 if (reqp == ascq->q_first[tid]) {
6012 ret = ASC_TRUE;
6013 ascq->q_first[tid] = REQPNEXT(reqp);
6014 /* If the queue is now empty, clear its bit and the last pointer. */
6015 if (ascq->q_first[tid] == NULL) {
6016 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
6017 ASC_ASSERT(ascq->q_last[tid] == reqp);
6018 ascq->q_last[tid] = NULL;
6019 }
6020 } else if (ascq->q_first[tid] != NULL) {
6021 ASC_ASSERT(ascq->q_last[tid] != NULL);
6022 /*
6023 * Because the case of 'reqp' being the first entry has been
6024 * handled above and it is known the queue is not empty, if
6025 * 'reqp' is found on the queue it is guaranteed the queue will
6026 * not become empty and that 'q_first[tid]' will not be changed.
6027 *
6028 * Set 'prevp' to the first entry, 'currp' to the second entry,
6029 * and search for 'reqp'.
6030 */
6031 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
6032 currp; prevp = currp, currp = REQPNEXT(currp)) {
6033 if (currp == reqp) {
6034 ret = ASC_TRUE;
6035 prevp->host_scribble =
6036 (unsigned char *)REQPNEXT(currp);
6037 reqp->host_scribble = NULL;
6038 if (ascq->q_last[tid] == reqp) {
6039 ascq->q_last[tid] = prevp;
6040 }
6041 break;
6042 }
6043 }
6044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006046 /* Maintain request queue statistics. */
6047 if (ret == ASC_TRUE) {
6048 ascq->q_cur_cnt[tid]--;
6049 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
6050 }
6051 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006053 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
6054 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055}
6056
6057/*
6058 * Execute as many queued requests as possible for the specified queue.
6059 *
6060 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
6061 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006062static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006064 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
6065 REQP reqp;
6066 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006068 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
6069 /*
6070 * Execute queued commands for devices attached to
6071 * the current board in round-robin fashion.
6072 */
6073 scan_tidmask = ascq->q_tidmask;
6074 do {
6075 for (i = 0; i <= ADV_MAX_TID; i++) {
6076 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
6077 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
6078 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6079 } else
6080 if (asc_execute_scsi_cmnd
6081 ((struct scsi_cmnd *)reqp)
6082 == ASC_BUSY) {
6083 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6084 /*
6085 * The request returned ASC_BUSY. Enqueue at the front of
6086 * target's waiting list to maintain correct ordering.
6087 */
6088 asc_enqueue(ascq, reqp, ASC_FRONT);
6089 }
6090 }
6091 }
6092 } while (scan_tidmask);
6093 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094}
6095
6096#ifdef CONFIG_PROC_FS
6097/*
6098 * asc_prt_board_devices()
6099 *
6100 * Print driver information for devices attached to the board.
6101 *
6102 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6103 * cf. asc_prt_line().
6104 *
6105 * Return the number of characters copied into 'cp'. No more than
6106 * 'cplen' characters will be copied to 'cp'.
6107 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006108static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006109{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006110 asc_board_t *boardp;
6111 int leftlen;
6112 int totlen;
6113 int len;
6114 int chip_scsi_id;
6115 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006117 boardp = ASC_BOARDP(shost);
6118 leftlen = cplen;
6119 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006121 len = asc_prt_line(cp, leftlen,
6122 "\nDevice Information for AdvanSys SCSI Host %d:\n",
6123 shost->host_no);
6124 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006126 if (ASC_NARROW_BOARD(boardp)) {
6127 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6128 } else {
6129 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006131
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006132 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6133 ASC_PRT_NEXT();
6134 for (i = 0; i <= ADV_MAX_TID; i++) {
6135 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6136 len = asc_prt_line(cp, leftlen, " %X,", i);
6137 ASC_PRT_NEXT();
6138 }
6139 }
6140 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6141 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006142
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006143 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144}
6145
6146/*
6147 * Display Wide Board BIOS Information.
6148 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006149static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006151 asc_board_t *boardp;
6152 int leftlen;
6153 int totlen;
6154 int len;
6155 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006157 boardp = ASC_BOARDP(shost);
6158 leftlen = cplen;
6159 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006161 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6162 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006164 /*
6165 * If the BIOS saved a valid signature, then fill in
6166 * the BIOS code segment base address.
6167 */
6168 if (boardp->bios_signature != 0x55AA) {
6169 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6170 ASC_PRT_NEXT();
6171 len = asc_prt_line(cp, leftlen,
6172 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6173 ASC_PRT_NEXT();
6174 len = asc_prt_line(cp, leftlen,
6175 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6176 ASC_PRT_NEXT();
6177 } else {
6178 major = (boardp->bios_version >> 12) & 0xF;
6179 minor = (boardp->bios_version >> 8) & 0xF;
6180 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006181
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006182 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6183 major, minor,
6184 letter >= 26 ? '?' : letter + 'A');
6185 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006186
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006187 /*
6188 * Current available ROM BIOS release is 3.1I for UW
6189 * and 3.2I for U2W. This code doesn't differentiate
6190 * UW and U2W boards.
6191 */
6192 if (major < 3 || (major <= 3 && minor < 1) ||
6193 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6194 len = asc_prt_line(cp, leftlen,
6195 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6196 ASC_PRT_NEXT();
6197 len = asc_prt_line(cp, leftlen,
6198 "ftp://ftp.connectcom.net/pub\n");
6199 ASC_PRT_NEXT();
6200 }
6201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006202
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006203 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204}
6205
6206/*
6207 * Add serial number to information bar if signature AAh
6208 * is found in at bit 15-9 (7 bits) of word 1.
6209 *
6210 * Serial Number consists fo 12 alpha-numeric digits.
6211 *
6212 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6213 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6214 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6215 * 5 - Product revision (A-J) Word0: " "
6216 *
6217 * Signature Word1: 15-9 (7 bits)
6218 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6219 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6220 *
6221 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6222 *
6223 * Note 1: Only production cards will have a serial number.
6224 *
6225 * Note 2: Signature is most significant 7 bits (0xFE).
6226 *
6227 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6228 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006229static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006230{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006231 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006233 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6234 return ASC_FALSE;
6235 } else {
6236 /*
6237 * First word - 6 digits.
6238 */
6239 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006241 /* Product type - 1st digit. */
6242 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6243 /* Product type is P=Prototype */
6244 *cp += 0x8;
6245 }
6246 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006248 /* Manufacturing location - 2nd digit. */
6249 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006251 /* Product ID - 3rd, 4th digits. */
6252 num = w & 0x3FF;
6253 *cp++ = '0' + (num / 100);
6254 num %= 100;
6255 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006257 /* Product revision - 5th digit. */
6258 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006260 /*
6261 * Second word
6262 */
6263 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006265 /*
6266 * Year - 6th digit.
6267 *
6268 * If bit 15 of third word is set, then the
6269 * last digit of the year is greater than 7.
6270 */
6271 if (serialnum[2] & 0x8000) {
6272 *cp++ = '8' + ((w & 0x1C0) >> 6);
6273 } else {
6274 *cp++ = '0' + ((w & 0x1C0) >> 6);
6275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006277 /* Week of year - 7th, 8th digits. */
6278 num = w & 0x003F;
6279 *cp++ = '0' + num / 10;
6280 num %= 10;
6281 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006283 /*
6284 * Third word
6285 */
6286 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006287
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006288 /* Serial number - 9th digit. */
6289 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006291 /* 10th, 11th, 12th digits. */
6292 num = w % 1000;
6293 *cp++ = '0' + num / 100;
6294 num %= 100;
6295 *cp++ = '0' + num / 10;
6296 num %= 10;
6297 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006299 *cp = '\0'; /* Null Terminate the string. */
6300 return ASC_TRUE;
6301 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302}
6303
6304/*
6305 * asc_prt_asc_board_eeprom()
6306 *
6307 * Print board EEPROM configuration.
6308 *
6309 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6310 * cf. asc_prt_line().
6311 *
6312 * Return the number of characters copied into 'cp'. No more than
6313 * 'cplen' characters will be copied to 'cp'.
6314 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006315static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006317 asc_board_t *boardp;
6318 ASC_DVC_VAR *asc_dvc_varp;
6319 int leftlen;
6320 int totlen;
6321 int len;
6322 ASCEEP_CONFIG *ep;
6323 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006325 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006327 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006328
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006329 boardp = ASC_BOARDP(shost);
6330 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6331 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006333 leftlen = cplen;
6334 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006336 len = asc_prt_line(cp, leftlen,
6337 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6338 shost->host_no);
6339 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006341 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6342 == ASC_TRUE) {
6343 len =
6344 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6345 serialstr);
6346 ASC_PRT_NEXT();
6347 } else {
6348 if (ep->adapter_info[5] == 0xBB) {
6349 len = asc_prt_line(cp, leftlen,
6350 " Default Settings Used for EEPROM-less Adapter.\n");
6351 ASC_PRT_NEXT();
6352 } else {
6353 len = asc_prt_line(cp, leftlen,
6354 " Serial Number Signature Not Present.\n");
6355 ASC_PRT_NEXT();
6356 }
6357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006359 len = asc_prt_line(cp, leftlen,
6360 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6361 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6362 ep->max_tag_qng);
6363 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006365 len = asc_prt_line(cp, leftlen,
6366 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6367 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006369 len = asc_prt_line(cp, leftlen, " Target ID: ");
6370 ASC_PRT_NEXT();
6371 for (i = 0; i <= ASC_MAX_TID; i++) {
6372 len = asc_prt_line(cp, leftlen, " %d", i);
6373 ASC_PRT_NEXT();
6374 }
6375 len = asc_prt_line(cp, leftlen, "\n");
6376 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006378 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6379 ASC_PRT_NEXT();
6380 for (i = 0; i <= ASC_MAX_TID; i++) {
6381 len = asc_prt_line(cp, leftlen, " %c",
6382 (ep->
6383 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6384 'N');
6385 ASC_PRT_NEXT();
6386 }
6387 len = asc_prt_line(cp, leftlen, "\n");
6388 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006390 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6391 ASC_PRT_NEXT();
6392 for (i = 0; i <= ASC_MAX_TID; i++) {
6393 len = asc_prt_line(cp, leftlen, " %c",
6394 (ep->
6395 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6396 'N');
6397 ASC_PRT_NEXT();
6398 }
6399 len = asc_prt_line(cp, leftlen, "\n");
6400 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006402 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6403 ASC_PRT_NEXT();
6404 for (i = 0; i <= ASC_MAX_TID; i++) {
6405 len = asc_prt_line(cp, leftlen, " %c",
6406 (ep->
6407 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6408 'N');
6409 ASC_PRT_NEXT();
6410 }
6411 len = asc_prt_line(cp, leftlen, "\n");
6412 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006414 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6415 ASC_PRT_NEXT();
6416 for (i = 0; i <= ASC_MAX_TID; i++) {
6417 len = asc_prt_line(cp, leftlen, " %c",
6418 (ep->
6419 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6420 'N');
6421 ASC_PRT_NEXT();
6422 }
6423 len = asc_prt_line(cp, leftlen, "\n");
6424 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006425
6426#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006427 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6428 len = asc_prt_line(cp, leftlen,
6429 " Host ISA DMA speed: %d MB/S\n",
6430 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6431 ASC_PRT_NEXT();
6432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006433#endif /* CONFIG_ISA */
6434
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006435 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006436}
6437
6438/*
6439 * asc_prt_adv_board_eeprom()
6440 *
6441 * Print board EEPROM configuration.
6442 *
6443 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6444 * cf. asc_prt_line().
6445 *
6446 * Return the number of characters copied into 'cp'. No more than
6447 * 'cplen' characters will be copied to 'cp'.
6448 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006449static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006451 asc_board_t *boardp;
6452 ADV_DVC_VAR *adv_dvc_varp;
6453 int leftlen;
6454 int totlen;
6455 int len;
6456 int i;
6457 char *termstr;
6458 uchar serialstr[13];
6459 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6460 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6461 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6462 ushort word;
6463 ushort *wordp;
6464 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006465
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006466 boardp = ASC_BOARDP(shost);
6467 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6468 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6469 ep_3550 = &boardp->eep_config.adv_3550_eep;
6470 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6471 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6472 } else {
6473 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006475
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006476 leftlen = cplen;
6477 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006479 len = asc_prt_line(cp, leftlen,
6480 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6481 shost->host_no);
6482 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006483
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006484 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6485 wordp = &ep_3550->serial_number_word1;
6486 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6487 wordp = &ep_38C0800->serial_number_word1;
6488 } else {
6489 wordp = &ep_38C1600->serial_number_word1;
6490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006492 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6493 len =
6494 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6495 serialstr);
6496 ASC_PRT_NEXT();
6497 } else {
6498 len = asc_prt_line(cp, leftlen,
6499 " Serial Number Signature Not Present.\n");
6500 ASC_PRT_NEXT();
6501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006503 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6504 len = asc_prt_line(cp, leftlen,
6505 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6506 ep_3550->adapter_scsi_id,
6507 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6508 ASC_PRT_NEXT();
6509 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6510 len = asc_prt_line(cp, leftlen,
6511 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6512 ep_38C0800->adapter_scsi_id,
6513 ep_38C0800->max_host_qng,
6514 ep_38C0800->max_dvc_qng);
6515 ASC_PRT_NEXT();
6516 } else {
6517 len = asc_prt_line(cp, leftlen,
6518 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6519 ep_38C1600->adapter_scsi_id,
6520 ep_38C1600->max_host_qng,
6521 ep_38C1600->max_dvc_qng);
6522 ASC_PRT_NEXT();
6523 }
6524 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6525 word = ep_3550->termination;
6526 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6527 word = ep_38C0800->termination_lvd;
6528 } else {
6529 word = ep_38C1600->termination_lvd;
6530 }
6531 switch (word) {
6532 case 1:
6533 termstr = "Low Off/High Off";
6534 break;
6535 case 2:
6536 termstr = "Low Off/High On";
6537 break;
6538 case 3:
6539 termstr = "Low On/High On";
6540 break;
6541 default:
6542 case 0:
6543 termstr = "Automatic";
6544 break;
6545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006546
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006547 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6548 len = asc_prt_line(cp, leftlen,
6549 " termination: %u (%s), bios_ctrl: 0x%x\n",
6550 ep_3550->termination, termstr,
6551 ep_3550->bios_ctrl);
6552 ASC_PRT_NEXT();
6553 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6554 len = asc_prt_line(cp, leftlen,
6555 " termination: %u (%s), bios_ctrl: 0x%x\n",
6556 ep_38C0800->termination_lvd, termstr,
6557 ep_38C0800->bios_ctrl);
6558 ASC_PRT_NEXT();
6559 } else {
6560 len = asc_prt_line(cp, leftlen,
6561 " termination: %u (%s), bios_ctrl: 0x%x\n",
6562 ep_38C1600->termination_lvd, termstr,
6563 ep_38C1600->bios_ctrl);
6564 ASC_PRT_NEXT();
6565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006566
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006567 len = asc_prt_line(cp, leftlen, " Target ID: ");
6568 ASC_PRT_NEXT();
6569 for (i = 0; i <= ADV_MAX_TID; i++) {
6570 len = asc_prt_line(cp, leftlen, " %X", i);
6571 ASC_PRT_NEXT();
6572 }
6573 len = asc_prt_line(cp, leftlen, "\n");
6574 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006575
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006576 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6577 word = ep_3550->disc_enable;
6578 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6579 word = ep_38C0800->disc_enable;
6580 } else {
6581 word = ep_38C1600->disc_enable;
6582 }
6583 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6584 ASC_PRT_NEXT();
6585 for (i = 0; i <= ADV_MAX_TID; i++) {
6586 len = asc_prt_line(cp, leftlen, " %c",
6587 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6588 ASC_PRT_NEXT();
6589 }
6590 len = asc_prt_line(cp, leftlen, "\n");
6591 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006592
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006593 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6594 word = ep_3550->tagqng_able;
6595 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6596 word = ep_38C0800->tagqng_able;
6597 } else {
6598 word = ep_38C1600->tagqng_able;
6599 }
6600 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6601 ASC_PRT_NEXT();
6602 for (i = 0; i <= ADV_MAX_TID; i++) {
6603 len = asc_prt_line(cp, leftlen, " %c",
6604 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6605 ASC_PRT_NEXT();
6606 }
6607 len = asc_prt_line(cp, leftlen, "\n");
6608 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006609
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006610 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6611 word = ep_3550->start_motor;
6612 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6613 word = ep_38C0800->start_motor;
6614 } else {
6615 word = ep_38C1600->start_motor;
6616 }
6617 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6618 ASC_PRT_NEXT();
6619 for (i = 0; i <= ADV_MAX_TID; i++) {
6620 len = asc_prt_line(cp, leftlen, " %c",
6621 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6622 ASC_PRT_NEXT();
6623 }
6624 len = asc_prt_line(cp, leftlen, "\n");
6625 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006627 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6628 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6629 ASC_PRT_NEXT();
6630 for (i = 0; i <= ADV_MAX_TID; i++) {
6631 len = asc_prt_line(cp, leftlen, " %c",
6632 (ep_3550->
6633 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6634 'Y' : 'N');
6635 ASC_PRT_NEXT();
6636 }
6637 len = asc_prt_line(cp, leftlen, "\n");
6638 ASC_PRT_NEXT();
6639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006641 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6642 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6643 ASC_PRT_NEXT();
6644 for (i = 0; i <= ADV_MAX_TID; i++) {
6645 len = asc_prt_line(cp, leftlen, " %c",
6646 (ep_3550->
6647 ultra_able & ADV_TID_TO_TIDMASK(i))
6648 ? 'Y' : 'N');
6649 ASC_PRT_NEXT();
6650 }
6651 len = asc_prt_line(cp, leftlen, "\n");
6652 ASC_PRT_NEXT();
6653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006654
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006655 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6656 word = ep_3550->wdtr_able;
6657 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6658 word = ep_38C0800->wdtr_able;
6659 } else {
6660 word = ep_38C1600->wdtr_able;
6661 }
6662 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6663 ASC_PRT_NEXT();
6664 for (i = 0; i <= ADV_MAX_TID; i++) {
6665 len = asc_prt_line(cp, leftlen, " %c",
6666 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6667 ASC_PRT_NEXT();
6668 }
6669 len = asc_prt_line(cp, leftlen, "\n");
6670 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006672 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6673 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6674 len = asc_prt_line(cp, leftlen,
6675 " Synchronous Transfer Speed (Mhz):\n ");
6676 ASC_PRT_NEXT();
6677 for (i = 0; i <= ADV_MAX_TID; i++) {
6678 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006679
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006680 if (i == 0) {
6681 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6682 } else if (i == 4) {
6683 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6684 } else if (i == 8) {
6685 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6686 } else if (i == 12) {
6687 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6688 }
6689 switch (sdtr_speed & ADV_MAX_TID) {
6690 case 0:
6691 speed_str = "Off";
6692 break;
6693 case 1:
6694 speed_str = " 5";
6695 break;
6696 case 2:
6697 speed_str = " 10";
6698 break;
6699 case 3:
6700 speed_str = " 20";
6701 break;
6702 case 4:
6703 speed_str = " 40";
6704 break;
6705 case 5:
6706 speed_str = " 80";
6707 break;
6708 default:
6709 speed_str = "Unk";
6710 break;
6711 }
6712 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6713 ASC_PRT_NEXT();
6714 if (i == 7) {
6715 len = asc_prt_line(cp, leftlen, "\n ");
6716 ASC_PRT_NEXT();
6717 }
6718 sdtr_speed >>= 4;
6719 }
6720 len = asc_prt_line(cp, leftlen, "\n");
6721 ASC_PRT_NEXT();
6722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006723
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006724 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006725}
6726
6727/*
6728 * asc_prt_driver_conf()
6729 *
6730 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6731 * cf. asc_prt_line().
6732 *
6733 * Return the number of characters copied into 'cp'. No more than
6734 * 'cplen' characters will be copied to 'cp'.
6735 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006736static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006737{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006738 asc_board_t *boardp;
6739 int leftlen;
6740 int totlen;
6741 int len;
6742 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006743
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006744 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006745
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006746 leftlen = cplen;
6747 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006748
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006749 len = asc_prt_line(cp, leftlen,
6750 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6751 shost->host_no);
6752 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006754 len = asc_prt_line(cp, leftlen,
6755 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6756 shost->host_busy, shost->last_reset, shost->max_id,
6757 shost->max_lun, shost->max_channel);
6758 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006759
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006760 len = asc_prt_line(cp, leftlen,
6761 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6762 shost->unique_id, shost->can_queue, shost->this_id,
6763 shost->sg_tablesize, shost->cmd_per_lun);
6764 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006765
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006766 len = asc_prt_line(cp, leftlen,
6767 " unchecked_isa_dma %d, use_clustering %d\n",
6768 shost->unchecked_isa_dma, shost->use_clustering);
6769 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006771 len = asc_prt_line(cp, leftlen,
6772 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6773 boardp->flags, boardp->last_reset, jiffies,
6774 boardp->asc_n_io_port);
6775 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006776
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006777 /* 'shost->n_io_port' may be truncated because it is only one byte. */
6778 len = asc_prt_line(cp, leftlen,
6779 " io_port 0x%x, n_io_port 0x%x\n",
6780 shost->io_port, shost->n_io_port);
6781 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006782
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006783 if (ASC_NARROW_BOARD(boardp)) {
6784 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6785 } else {
6786 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006788
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006789 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006790}
6791
6792/*
6793 * asc_prt_asc_board_info()
6794 *
6795 * Print dynamic board configuration information.
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_asc_board_info(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 chip_scsi_id;
6807 int leftlen;
6808 int totlen;
6809 int len;
6810 ASC_DVC_VAR *v;
6811 ASC_DVC_CFG *c;
6812 int i;
6813 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006814
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006815 boardp = ASC_BOARDP(shost);
6816 v = &boardp->dvc_var.asc_dvc_var;
6817 c = &boardp->dvc_cfg.asc_dvc_cfg;
6818 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006819
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006820 leftlen = cplen;
6821 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006822
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006823 len = asc_prt_line(cp, leftlen,
6824 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6825 shost->host_no);
6826 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006827
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006828 len = asc_prt_line(cp, leftlen,
6829 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6830 c->chip_version, c->lib_version, c->lib_serial_no,
6831 c->mcode_date);
6832 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006834 len = asc_prt_line(cp, leftlen,
6835 " mcode_version 0x%x, err_code %u\n",
6836 c->mcode_version, v->err_code);
6837 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006838
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006839 /* Current number of commands waiting for the host. */
6840 len = asc_prt_line(cp, leftlen,
6841 " Total Command Pending: %d\n", v->cur_total_qng);
6842 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006843
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006844 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6845 ASC_PRT_NEXT();
6846 for (i = 0; i <= ASC_MAX_TID; i++) {
6847 if ((chip_scsi_id == i) ||
6848 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6849 continue;
6850 }
6851 len = asc_prt_line(cp, leftlen, " %X:%c",
6852 i,
6853 (v->
6854 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6855 'Y' : 'N');
6856 ASC_PRT_NEXT();
6857 }
6858 len = asc_prt_line(cp, leftlen, "\n");
6859 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006860
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006861 /* Current number of commands waiting for a device. */
6862 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6863 ASC_PRT_NEXT();
6864 for (i = 0; i <= ASC_MAX_TID; i++) {
6865 if ((chip_scsi_id == i) ||
6866 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6867 continue;
6868 }
6869 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6870 ASC_PRT_NEXT();
6871 }
6872 len = asc_prt_line(cp, leftlen, "\n");
6873 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006874
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006875 /* Current limit on number of commands that can be sent to a device. */
6876 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6877 ASC_PRT_NEXT();
6878 for (i = 0; i <= ASC_MAX_TID; i++) {
6879 if ((chip_scsi_id == i) ||
6880 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6881 continue;
6882 }
6883 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
6884 ASC_PRT_NEXT();
6885 }
6886 len = asc_prt_line(cp, leftlen, "\n");
6887 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006888
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006889 /* Indicate whether the device has returned queue full status. */
6890 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
6891 ASC_PRT_NEXT();
6892 for (i = 0; i <= ASC_MAX_TID; i++) {
6893 if ((chip_scsi_id == i) ||
6894 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6895 continue;
6896 }
6897 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
6898 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
6899 i, boardp->queue_full_cnt[i]);
6900 } else {
6901 len = asc_prt_line(cp, leftlen, " %X:N", i);
6902 }
6903 ASC_PRT_NEXT();
6904 }
6905 len = asc_prt_line(cp, leftlen, "\n");
6906 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006908 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6909 ASC_PRT_NEXT();
6910 for (i = 0; i <= ASC_MAX_TID; i++) {
6911 if ((chip_scsi_id == i) ||
6912 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6913 continue;
6914 }
6915 len = asc_prt_line(cp, leftlen, " %X:%c",
6916 i,
6917 (v->
6918 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6919 'N');
6920 ASC_PRT_NEXT();
6921 }
6922 len = asc_prt_line(cp, leftlen, "\n");
6923 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006924
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006925 for (i = 0; i <= ASC_MAX_TID; i++) {
6926 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006927
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006928 if ((chip_scsi_id == i) ||
6929 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6930 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
6931 continue;
6932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006933
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006934 len = asc_prt_line(cp, leftlen, " %X:", i);
6935 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006936
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006937 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
6938 len = asc_prt_line(cp, leftlen, " Asynchronous");
6939 ASC_PRT_NEXT();
6940 } else {
6941 syn_period_ix =
6942 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
6943 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006944
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006945 len = asc_prt_line(cp, leftlen,
6946 " Transfer Period Factor: %d (%d.%d Mhz),",
6947 v->sdtr_period_tbl[syn_period_ix],
6948 250 /
6949 v->sdtr_period_tbl[syn_period_ix],
6950 ASC_TENTHS(250,
6951 v->
6952 sdtr_period_tbl
6953 [syn_period_ix]));
6954 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006955
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006956 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6957 boardp->
6958 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
6959 ASC_PRT_NEXT();
6960 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006961
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006962 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6963 len = asc_prt_line(cp, leftlen, "*\n");
6964 renegotiate = 1;
6965 } else {
6966 len = asc_prt_line(cp, leftlen, "\n");
6967 }
6968 ASC_PRT_NEXT();
6969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006970
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006971 if (renegotiate) {
6972 len = asc_prt_line(cp, leftlen,
6973 " * = Re-negotiation pending before next command.\n");
6974 ASC_PRT_NEXT();
6975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006976
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006977 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006978}
6979
6980/*
6981 * asc_prt_adv_board_info()
6982 *
6983 * Print dynamic board configuration information.
6984 *
6985 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6986 * cf. asc_prt_line().
6987 *
6988 * Return the number of characters copied into 'cp'. No more than
6989 * 'cplen' characters will be copied to 'cp'.
6990 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006991static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006992{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006993 asc_board_t *boardp;
6994 int leftlen;
6995 int totlen;
6996 int len;
6997 int i;
6998 ADV_DVC_VAR *v;
6999 ADV_DVC_CFG *c;
7000 AdvPortAddr iop_base;
7001 ushort chip_scsi_id;
7002 ushort lramword;
7003 uchar lrambyte;
7004 ushort tagqng_able;
7005 ushort sdtr_able, wdtr_able;
7006 ushort wdtr_done, sdtr_done;
7007 ushort period = 0;
7008 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007009
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007010 boardp = ASC_BOARDP(shost);
7011 v = &boardp->dvc_var.adv_dvc_var;
7012 c = &boardp->dvc_cfg.adv_dvc_cfg;
7013 iop_base = v->iop_base;
7014 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007015
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007016 leftlen = cplen;
7017 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007018
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007019 len = asc_prt_line(cp, leftlen,
7020 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
7021 shost->host_no);
7022 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007023
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007024 len = asc_prt_line(cp, leftlen,
7025 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
7026 v->iop_base,
7027 AdvReadWordRegister(iop_base,
7028 IOPW_SCSI_CFG1) & CABLE_DETECT,
7029 v->err_code);
7030 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007031
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007032 len = asc_prt_line(cp, leftlen,
7033 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
7034 c->chip_version, c->lib_version, c->mcode_date,
7035 c->mcode_version);
7036 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007037
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007038 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
7039 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
7040 ASC_PRT_NEXT();
7041 for (i = 0; i <= ADV_MAX_TID; i++) {
7042 if ((chip_scsi_id == i) ||
7043 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7044 continue;
7045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007046
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007047 len = asc_prt_line(cp, leftlen, " %X:%c",
7048 i,
7049 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7050 'N');
7051 ASC_PRT_NEXT();
7052 }
7053 len = asc_prt_line(cp, leftlen, "\n");
7054 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007055
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007056 len = asc_prt_line(cp, leftlen, " Queue Limit:");
7057 ASC_PRT_NEXT();
7058 for (i = 0; i <= ADV_MAX_TID; i++) {
7059 if ((chip_scsi_id == i) ||
7060 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7061 continue;
7062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007063
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007064 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
7065 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007066
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007067 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
7068 ASC_PRT_NEXT();
7069 }
7070 len = asc_prt_line(cp, leftlen, "\n");
7071 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007072
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007073 len = asc_prt_line(cp, leftlen, " Command Pending:");
7074 ASC_PRT_NEXT();
7075 for (i = 0; i <= ADV_MAX_TID; i++) {
7076 if ((chip_scsi_id == i) ||
7077 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7078 continue;
7079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007081 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
7082 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007083
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007084 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
7085 ASC_PRT_NEXT();
7086 }
7087 len = asc_prt_line(cp, leftlen, "\n");
7088 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007089
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007090 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
7091 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
7092 ASC_PRT_NEXT();
7093 for (i = 0; i <= ADV_MAX_TID; i++) {
7094 if ((chip_scsi_id == i) ||
7095 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7096 continue;
7097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007098
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007099 len = asc_prt_line(cp, leftlen, " %X:%c",
7100 i,
7101 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7102 'N');
7103 ASC_PRT_NEXT();
7104 }
7105 len = asc_prt_line(cp, leftlen, "\n");
7106 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007107
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007108 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
7109 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
7110 ASC_PRT_NEXT();
7111 for (i = 0; i <= ADV_MAX_TID; i++) {
7112 if ((chip_scsi_id == i) ||
7113 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7114 continue;
7115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007117 AdvReadWordLram(iop_base,
7118 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7119 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007120
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007121 len = asc_prt_line(cp, leftlen, " %X:%d",
7122 i, (lramword & 0x8000) ? 16 : 8);
7123 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007125 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
7126 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7127 len = asc_prt_line(cp, leftlen, "*");
7128 ASC_PRT_NEXT();
7129 renegotiate = 1;
7130 }
7131 }
7132 len = asc_prt_line(cp, leftlen, "\n");
7133 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007134
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007135 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7136 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7137 ASC_PRT_NEXT();
7138 for (i = 0; i <= ADV_MAX_TID; i++) {
7139 if ((chip_scsi_id == i) ||
7140 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7141 continue;
7142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007143
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007144 len = asc_prt_line(cp, leftlen, " %X:%c",
7145 i,
7146 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7147 'N');
7148 ASC_PRT_NEXT();
7149 }
7150 len = asc_prt_line(cp, leftlen, "\n");
7151 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007152
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007153 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7154 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007155
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007156 AdvReadWordLram(iop_base,
7157 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7158 lramword);
7159 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007160
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007161 if ((chip_scsi_id == i) ||
7162 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7163 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7164 continue;
7165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007167 len = asc_prt_line(cp, leftlen, " %X:", i);
7168 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007170 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7171 len = asc_prt_line(cp, leftlen, " Asynchronous");
7172 ASC_PRT_NEXT();
7173 } else {
7174 len =
7175 asc_prt_line(cp, leftlen,
7176 " Transfer Period Factor: ");
7177 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007178
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007179 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7180 len =
7181 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7182 ASC_PRT_NEXT();
7183 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7184 len =
7185 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7186 ASC_PRT_NEXT();
7187 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007188
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007189 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007190
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007191 if (period == 0) { /* Should never happen. */
7192 len =
7193 asc_prt_line(cp, leftlen,
7194 "%d (? Mhz), ");
7195 ASC_PRT_NEXT();
7196 } else {
7197 len = asc_prt_line(cp, leftlen,
7198 "%d (%d.%d Mhz),",
7199 period, 250 / period,
7200 ASC_TENTHS(250,
7201 period));
7202 ASC_PRT_NEXT();
7203 }
7204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007206 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7207 lramword & 0x1F);
7208 ASC_PRT_NEXT();
7209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007210
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007211 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7212 len = asc_prt_line(cp, leftlen, "*\n");
7213 renegotiate = 1;
7214 } else {
7215 len = asc_prt_line(cp, leftlen, "\n");
7216 }
7217 ASC_PRT_NEXT();
7218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007220 if (renegotiate) {
7221 len = asc_prt_line(cp, leftlen,
7222 " * = Re-negotiation pending before next command.\n");
7223 ASC_PRT_NEXT();
7224 }
7225
7226 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007227}
7228
7229/*
7230 * asc_proc_copy()
7231 *
7232 * Copy proc information to a read buffer taking into account the current
7233 * read offset in the file and the remaining space in the read buffer.
7234 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007235static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007236asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007237 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007238{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007239 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007240
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007241 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7242 (unsigned)offset, (unsigned)advoffset, cplen);
7243 if (offset <= advoffset) {
7244 /* Read offset below current offset, copy everything. */
7245 cnt = min(cplen, leftlen);
7246 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7247 (ulong)curbuf, (ulong)cp, cnt);
7248 memcpy(curbuf, cp, cnt);
7249 } else if (offset < advoffset + cplen) {
7250 /* Read offset within current range, partial copy. */
7251 cnt = (advoffset + cplen) - offset;
7252 cp = (cp + cplen) - cnt;
7253 cnt = min(cnt, leftlen);
7254 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7255 (ulong)curbuf, (ulong)cp, cnt);
7256 memcpy(curbuf, cp, cnt);
7257 }
7258 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007259}
7260
7261/*
7262 * asc_prt_line()
7263 *
7264 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7265 *
7266 * Return 0 if printing to the console, otherwise return the number of
7267 * bytes written to the buffer.
7268 *
7269 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7270 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7271 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007272static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007273{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007274 va_list args;
7275 int ret;
7276 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007277
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007278 va_start(args, fmt);
7279 ret = vsprintf(s, fmt, args);
7280 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7281 if (buf == NULL) {
7282 (void)printk(s);
7283 ret = 0;
7284 } else {
7285 ret = min(buflen, ret);
7286 memcpy(buf, s, ret);
7287 }
7288 va_end(args);
7289 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290}
7291#endif /* CONFIG_PROC_FS */
7292
Linus Torvalds1da177e2005-04-16 15:20:36 -07007293/*
7294 * --- Functions Required by the Asc Library
7295 */
7296
7297/*
7298 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7299 * global variable which is incremented once every 5 ms
7300 * from a timer interrupt, because this function may be
7301 * called when interrupts are disabled.
7302 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007303static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007304{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007305 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7306 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307}
7308
7309/*
7310 * Currently and inline noop but leave as a placeholder.
7311 * Leave DvcEnterCritical() as a noop placeholder.
7312 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007313static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007314{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007315 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007316}
7317
7318/*
7319 * Critical sections are all protected by the board spinlock.
7320 * Leave DvcLeaveCritical() as a noop placeholder.
7321 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007322static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007323{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007324 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007325}
7326
7327/*
7328 * void
7329 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7330 *
7331 * Calling/Exit State:
7332 * none
7333 *
7334 * Description:
7335 * Output an ASC_SCSI_Q structure to the chip
7336 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007337static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007338DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7339{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007340 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007341
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007342 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7343 AscSetChipLramAddr(iop_base, s_addr);
7344 for (i = 0; i < 2 * words; i += 2) {
7345 if (i == 4 || i == 20) {
7346 continue;
7347 }
7348 outpw(iop_base + IOP_RAM_DATA,
7349 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007351}
7352
7353/*
7354 * void
7355 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7356 *
7357 * Calling/Exit State:
7358 * none
7359 *
7360 * Description:
7361 * Input an ASC_QDONE_INFO structure from the chip
7362 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007363static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007364DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7365{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007366 int i;
7367 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007368
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007369 AscSetChipLramAddr(iop_base, s_addr);
7370 for (i = 0; i < 2 * words; i += 2) {
7371 if (i == 10) {
7372 continue;
7373 }
7374 word = inpw(iop_base + IOP_RAM_DATA);
7375 inbuf[i] = word & 0xff;
7376 inbuf[i + 1] = (word >> 8) & 0xff;
7377 }
7378 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007379}
7380
7381/*
7382 * Read a PCI configuration byte.
7383 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007384static uchar __devinit DvcReadPCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007385{
7386#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007387 uchar byte_data;
7388 pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
7389 return byte_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007390#else /* !defined(CONFIG_PCI) */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007391 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007392#endif /* !defined(CONFIG_PCI) */
7393}
7394
7395/*
7396 * Write a PCI configuration byte.
7397 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007398static void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007399DvcWritePCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007400{
7401#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007402 pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007403#endif /* CONFIG_PCI */
7404}
7405
7406/*
7407 * Return the BIOS address of the adapter at the specified
7408 * I/O port and with the specified bus type.
7409 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007410static ushort __devinit AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007411{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007412 ushort cfg_lsw;
7413 ushort bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007414
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007415 /*
7416 * The PCI BIOS is re-located by the motherboard BIOS. Because
7417 * of this the driver can not determine where a PCI BIOS is
7418 * loaded and executes.
7419 */
7420 if (bus_type & ASC_IS_PCI) {
7421 return (0);
7422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007423#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007424 if ((bus_type & ASC_IS_EISA) != 0) {
7425 cfg_lsw = AscGetEisaChipCfg(iop_base);
7426 cfg_lsw &= 0x000F;
7427 bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
7428 (cfg_lsw * ASC_BIOS_BANK_SIZE));
7429 return (bios_addr);
7430 } /* if */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007431#endif /* CONFIG_ISA */
7432
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007433 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007434
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007435 /*
7436 * ISA PnP uses the top bit as the 32K BIOS flag
7437 */
7438 if (bus_type == ASC_IS_ISAPNP) {
7439 cfg_lsw &= 0x7FFF;
7440 }
7441 /* if */
7442 bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
7443 ASC_BIOS_MIN_ADDR);
7444 return (bios_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007445}
7446
Linus Torvalds1da177e2005-04-16 15:20:36 -07007447/*
7448 * --- Functions Required by the Adv Library
7449 */
7450
7451/*
7452 * DvcGetPhyAddr()
7453 *
7454 * Return the physical address of 'vaddr' and set '*lenp' to the
7455 * number of physically contiguous bytes that follow 'vaddr'.
7456 * 'flag' indicates the type of structure whose physical address
7457 * is being translated.
7458 *
7459 * Note: Because Linux currently doesn't page the kernel and all
7460 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7461 */
7462ADV_PADDR
7463DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007464 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007465{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007466 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007467
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007468 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007469
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007470 ASC_DBG4(4,
7471 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7472 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7473 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007474
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007475 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007476}
7477
7478/*
7479 * Read a PCI configuration byte.
7480 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007481static uchar __devinit DvcAdvReadPCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007482{
7483#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007484 uchar byte_data;
7485 pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
7486 return byte_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007487#else /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007488 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007489#endif /* CONFIG_PCI */
7490}
7491
7492/*
7493 * Write a PCI configuration byte.
7494 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007495static void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007496DvcAdvWritePCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007497{
7498#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007499 pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007500#else /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007501 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007502#endif /* CONFIG_PCI */
7503}
7504
7505/*
7506 * --- Tracing and Debugging Functions
7507 */
7508
7509#ifdef ADVANSYS_STATS
7510#ifdef CONFIG_PROC_FS
7511/*
7512 * asc_prt_board_stats()
7513 *
7514 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7515 * cf. asc_prt_line().
7516 *
7517 * Return the number of characters copied into 'cp'. No more than
7518 * 'cplen' characters will be copied to 'cp'.
7519 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007520static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007521{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007522 int leftlen;
7523 int totlen;
7524 int len;
7525 struct asc_stats *s;
7526 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007527
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007528 leftlen = cplen;
7529 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007530
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007531 boardp = ASC_BOARDP(shost);
7532 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007533
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007534 len = asc_prt_line(cp, leftlen,
7535 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7536 shost->host_no);
7537 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007538
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007539 len = asc_prt_line(cp, leftlen,
7540 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7541 s->queuecommand, s->reset, s->biosparam,
7542 s->interrupt);
7543 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007544
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007545 len = asc_prt_line(cp, leftlen,
7546 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7547 s->callback, s->done, s->build_error,
7548 s->adv_build_noreq, s->adv_build_nosg);
7549 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007550
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007551 len = asc_prt_line(cp, leftlen,
7552 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7553 s->exe_noerror, s->exe_busy, s->exe_error,
7554 s->exe_unknown);
7555 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007556
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007557 /*
7558 * Display data transfer statistics.
7559 */
7560 if (s->cont_cnt > 0) {
7561 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7562 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007563
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007564 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7565 s->cont_xfer / 2,
7566 ASC_TENTHS(s->cont_xfer, 2));
7567 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007568
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007569 /* Contiguous transfer average size */
7570 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7571 (s->cont_xfer / 2) / s->cont_cnt,
7572 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7573 ASC_PRT_NEXT();
7574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007575
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007576 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007577
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007578 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7579 s->sg_cnt, s->sg_elem);
7580 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007581
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007582 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7583 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7584 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007585
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007586 /* Scatter gather transfer statistics */
7587 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7588 s->sg_elem / s->sg_cnt,
7589 ASC_TENTHS(s->sg_elem, s->sg_cnt));
7590 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007592 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
7593 (s->sg_xfer / 2) / s->sg_elem,
7594 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7595 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007596
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007597 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7598 (s->sg_xfer / 2) / s->sg_cnt,
7599 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7600 ASC_PRT_NEXT();
7601 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007602
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007603 /*
7604 * Display request queuing statistics.
7605 */
7606 len = asc_prt_line(cp, leftlen,
7607 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7608 HZ);
7609 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007610
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007611 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007612}
7613
7614/*
7615 * asc_prt_target_stats()
7616 *
7617 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7618 * cf. asc_prt_line().
7619 *
7620 * This is separated from asc_prt_board_stats because a full set
7621 * of targets will overflow ASC_PRTBUF_SIZE.
7622 *
7623 * Return the number of characters copied into 'cp'. No more than
7624 * 'cplen' characters will be copied to 'cp'.
7625 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007626static int
7627asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007628{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007629 int leftlen;
7630 int totlen;
7631 int len;
7632 struct asc_stats *s;
7633 ushort chip_scsi_id;
7634 asc_board_t *boardp;
7635 asc_queue_t *active;
7636 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007637
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007638 leftlen = cplen;
7639 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007641 boardp = ASC_BOARDP(shost);
7642 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007643
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007644 active = &ASC_BOARDP(shost)->active;
7645 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007646
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007647 if (ASC_NARROW_BOARD(boardp)) {
7648 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7649 } else {
7650 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007652
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007653 if ((chip_scsi_id == tgt_id) ||
7654 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7655 return 0;
7656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007657
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007658 do {
7659 if (active->q_tot_cnt[tgt_id] > 0
7660 || waiting->q_tot_cnt[tgt_id] > 0) {
7661 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
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,
7665 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7666 active->q_cur_cnt[tgt_id],
7667 active->q_max_cnt[tgt_id],
7668 active->q_tot_cnt[tgt_id],
7669 active->q_min_tim[tgt_id],
7670 active->q_max_tim[tgt_id],
7671 (active->q_tot_cnt[tgt_id] ==
7672 0) ? 0 : (active->
7673 q_tot_tim[tgt_id] /
7674 active->
7675 q_tot_cnt[tgt_id]),
7676 (active->q_tot_cnt[tgt_id] ==
7677 0) ? 0 : ASC_TENTHS(active->
7678 q_tot_tim
7679 [tgt_id],
7680 active->
7681 q_tot_cnt
7682 [tgt_id]));
7683 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007684
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007685 len = asc_prt_line(cp, leftlen,
7686 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7687 waiting->q_cur_cnt[tgt_id],
7688 waiting->q_max_cnt[tgt_id],
7689 waiting->q_tot_cnt[tgt_id],
7690 waiting->q_min_tim[tgt_id],
7691 waiting->q_max_tim[tgt_id],
7692 (waiting->q_tot_cnt[tgt_id] ==
7693 0) ? 0 : (waiting->
7694 q_tot_tim[tgt_id] /
7695 waiting->
7696 q_tot_cnt[tgt_id]),
7697 (waiting->q_tot_cnt[tgt_id] ==
7698 0) ? 0 : ASC_TENTHS(waiting->
7699 q_tot_tim
7700 [tgt_id],
7701 waiting->
7702 q_tot_cnt
7703 [tgt_id]));
7704 ASC_PRT_NEXT();
7705 }
7706 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007708 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007709}
7710#endif /* CONFIG_PROC_FS */
7711#endif /* ADVANSYS_STATS */
7712
7713#ifdef ADVANSYS_DEBUG
7714/*
7715 * asc_prt_scsi_host()
7716 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007717static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007718{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007719 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007720
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007721 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007722
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007723 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7724 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7725 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007726
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007727 printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
7728 (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007729
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007730 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7731 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007732
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007733 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7734 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007735
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007736 if (ASC_NARROW_BOARD(boardp)) {
7737 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7738 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7739 } else {
7740 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7741 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7742 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007743}
7744
7745/*
7746 * asc_prt_scsi_cmnd()
7747 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007748static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007749{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007750 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007752 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7753 (ulong)s->device->host, (ulong)s->device, s->device->id,
7754 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007755
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007756 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007757
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007758 printk("sc_data_direction %u, resid %d\n",
7759 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007760
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007761 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007763 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7764 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007765
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007766 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007767
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007768 printk
7769 (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
7770 (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble,
7771 s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007772
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007773 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007774}
7775
7776/*
7777 * asc_prt_asc_dvc_var()
7778 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007779static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007780{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007781 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007782
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007783 printk
7784 (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
7785 h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007787 printk
7788 (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
7789 h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback,
7790 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007791
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007792 printk
7793 (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
7794 (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng,
7795 (unsigned)h->unit_not_ready, (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007796
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007797 printk
7798 (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
7799 (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor,
7800 (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007801
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007802 printk
7803 (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
7804 (unsigned)h->is_in_int, (unsigned)h->max_total_qng,
7805 (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007806
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007807 printk
7808 (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
7809 (unsigned)h->last_q_shortage, (unsigned)h->init_state,
7810 (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007811
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007812 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007813}
7814
7815/*
7816 * asc_prt_asc_dvc_cfg()
7817 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007818static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007819{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007820 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007821
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007822 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7823 h->can_tagged_qng, h->cmd_qng_enabled);
7824 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7825 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007826
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007827 printk
7828 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7829 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7830 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007832 printk
7833 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7834 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7835 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007836
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007837 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7838 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007839}
7840
7841/*
7842 * asc_prt_asc_scsi_q()
7843 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007844static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007845{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007846 ASC_SG_HEAD *sgp;
7847 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007848
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007849 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007851 printk
7852 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7853 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7854 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007855
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007856 printk
7857 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7858 (ulong)le32_to_cpu(q->q1.data_addr),
7859 (ulong)le32_to_cpu(q->q1.data_cnt),
7860 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007861
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007862 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
7863 (ulong)q->cdbptr, q->q2.cdb_len,
7864 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007865
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007866 if (q->sg_head) {
7867 sgp = q->sg_head;
7868 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
7869 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
7870 sgp->queue_cnt);
7871 for (i = 0; i < sgp->entry_cnt; i++) {
7872 printk(" [%u]: addr 0x%lx, bytes %lu\n",
7873 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
7874 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
7875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007876
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007878}
7879
7880/*
7881 * asc_prt_asc_qdone_info()
7882 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007883static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007884{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007885 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
7886 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
7887 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
7888 q->d2.tag_code);
7889 printk
7890 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
7891 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007892}
7893
7894/*
7895 * asc_prt_adv_dvc_var()
7896 *
7897 * Display an ADV_DVC_VAR structure.
7898 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007899static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007900{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007901 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007902
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007903 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
7904 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007905
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007906 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
7907 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
7908 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007909
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007910 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
7911 (unsigned)h->start_motor,
7912 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007913
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007914 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
7915 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
7916 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007917
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007918 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
7919 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007920
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007921 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
7922 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007923
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007924 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
7925 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007926}
7927
7928/*
7929 * asc_prt_adv_dvc_cfg()
7930 *
7931 * Display an ADV_DVC_CFG structure.
7932 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007933static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007934{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007935 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007936
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007937 printk(" disc_enable 0x%x, termination 0x%x\n",
7938 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007940 printk(" chip_version 0x%x, mcode_date 0x%x\n",
7941 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007942
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007943 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
7944 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007945
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007946 printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
7947 h->control_flag, h->pci_slot_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007948}
7949
7950/*
7951 * asc_prt_adv_scsi_req_q()
7952 *
7953 * Display an ADV_SCSI_REQ_Q structure.
7954 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007955static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007956{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007957 int sg_blk_cnt;
7958 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007959
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007960 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007961
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007962 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
7963 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007964
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007965 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
7966 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007967
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007968 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7969 (ulong)le32_to_cpu(q->data_cnt),
7970 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007971
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007972 printk
7973 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
7974 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007975
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007976 printk(" sg_working_ix 0x%x, target_cmd %u\n",
7977 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007978
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007979 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
7980 (ulong)le32_to_cpu(q->scsiq_rptr),
7981 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007982
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007983 /* Display the request's ADV_SG_BLOCK structures. */
7984 if (q->sg_list_ptr != NULL) {
7985 sg_blk_cnt = 0;
7986 while (1) {
7987 /*
7988 * 'sg_ptr' is a physical address. Convert it to a virtual
7989 * address by indexing 'sg_blk_cnt' into the virtual address
7990 * array 'sg_list_ptr'.
7991 *
7992 * XXX - Assumes all SG physical blocks are virtually contiguous.
7993 */
7994 sg_ptr =
7995 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
7996 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
7997 if (sg_ptr->sg_ptr == 0) {
7998 break;
7999 }
8000 sg_blk_cnt++;
8001 }
8002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008003}
8004
8005/*
8006 * asc_prt_adv_sgblock()
8007 *
8008 * Display an ADV_SG_BLOCK structure.
8009 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008010static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008011{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008012 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008013
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008014 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
8015 (ulong)b, sgblockno);
8016 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
8017 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
8018 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
8019 if (b->sg_ptr != 0) {
8020 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
8021 }
8022 for (i = 0; i < b->sg_cnt; i++) {
8023 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
8024 i, (ulong)b->sg_list[i].sg_addr,
8025 (ulong)b->sg_list[i].sg_count);
8026 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008027}
8028
8029/*
8030 * asc_prt_hex()
8031 *
8032 * Print hexadecimal output in 4 byte groupings 32 bytes
8033 * or 8 double-words per line.
8034 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008035static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008036{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008037 int i;
8038 int j;
8039 int k;
8040 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008042 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008043
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008044 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008045
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008046 /* Display a maximum of 8 double-words per line. */
8047 if ((k = (l - i) / 4) >= 8) {
8048 k = 8;
8049 m = 0;
8050 } else {
8051 m = (l - i) % 4;
8052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008053
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008054 for (j = 0; j < k; j++) {
8055 printk(" %2.2X%2.2X%2.2X%2.2X",
8056 (unsigned)s[i + (j * 4)],
8057 (unsigned)s[i + (j * 4) + 1],
8058 (unsigned)s[i + (j * 4) + 2],
8059 (unsigned)s[i + (j * 4) + 3]);
8060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008061
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008062 switch (m) {
8063 case 0:
8064 default:
8065 break;
8066 case 1:
8067 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
8068 break;
8069 case 2:
8070 printk(" %2.2X%2.2X",
8071 (unsigned)s[i + (j * 4)],
8072 (unsigned)s[i + (j * 4) + 1]);
8073 break;
8074 case 3:
8075 printk(" %2.2X%2.2X%2.2X",
8076 (unsigned)s[i + (j * 4) + 1],
8077 (unsigned)s[i + (j * 4) + 2],
8078 (unsigned)s[i + (j * 4) + 3]);
8079 break;
8080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008082 printk("\n");
8083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008084}
8085#endif /* ADVANSYS_DEBUG */
8086
8087/*
8088 * --- Asc Library Functions
8089 */
8090
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008091static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008092{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008093 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008094
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008095 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
8096 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
8097 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008098}
8099
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008100static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008101{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008102 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008103
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008104 if (AscGetChipScsiID(iop_base) == new_host_id) {
8105 return (new_host_id);
8106 }
8107 cfg_lsw = AscGetChipCfgLsw(iop_base);
8108 cfg_lsw &= 0xF8FF;
8109 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
8110 AscSetChipCfgLsw(iop_base, cfg_lsw);
8111 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008112}
8113
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008114static uchar __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008115{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008116 uchar sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008117
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008118 AscSetBank(iop_base, 1);
8119 sc = inp(iop_base + IOP_REG_SC);
8120 AscSetBank(iop_base, 0);
8121 return (sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008122}
8123
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008124static uchar __devinit AscGetChipVersion(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008125{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008126 if ((bus_type & ASC_IS_EISA) != 0) {
8127 PortAddr eisa_iop;
8128 uchar revision;
8129 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
8130 (PortAddr) ASC_EISA_REV_IOP_MASK;
8131 revision = inp(eisa_iop);
8132 return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision));
8133 }
8134 return (AscGetChipVerNo(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008135}
8136
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008137static ushort __devinit AscGetChipBusType(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008138{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008139 ushort chip_ver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008140
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008141 chip_ver = AscGetChipVerNo(iop_base);
8142 if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
8143 && (chip_ver <= ASC_CHIP_MAX_VER_VL)
8144 ) {
8145 if (((iop_base & 0x0C30) == 0x0C30)
8146 || ((iop_base & 0x0C50) == 0x0C50)
8147 ) {
8148 return (ASC_IS_EISA);
8149 }
8150 return (ASC_IS_VL);
8151 }
8152 if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
8153 (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
8154 if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
8155 return (ASC_IS_ISAPNP);
8156 }
8157 return (ASC_IS_ISA);
8158 } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
8159 (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
8160 return (ASC_IS_PCI);
8161 }
8162 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008163}
8164
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008165static ASC_DCNT
8166AscLoadMicroCode(PortAddr iop_base,
8167 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008168{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008169 ASC_DCNT chksum;
8170 ushort mcode_word_size;
8171 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008172
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008173 /* Write the microcode buffer starting at LRAM address 0. */
8174 mcode_word_size = (ushort)(mcode_size >> 1);
8175 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
8176 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008177
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008178 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
8179 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
8180 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
8181 (ushort)ASC_CODE_SEC_BEG,
8182 (ushort)((mcode_size -
8183 s_addr - (ushort)
8184 ASC_CODE_SEC_BEG) /
8185 2));
8186 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
8187 (ulong)mcode_chksum);
8188 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
8189 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
8190 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008191}
8192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008193static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008194{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008195 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008196
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008197 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
8198 iop_base, AscGetChipSignatureByte(iop_base));
8199 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
8200 ASC_DBG2(1,
8201 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
8202 iop_base, AscGetChipSignatureWord(iop_base));
8203 sig_word = AscGetChipSignatureWord(iop_base);
8204 if ((sig_word == (ushort)ASC_1000_ID0W) ||
8205 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
8206 return (1);
8207 }
8208 }
8209 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008210}
8211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008212static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata = {
8213 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
8214 ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
Linus Torvalds1da177e2005-04-16 15:20:36 -07008215};
8216
8217#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008218static uchar _isa_pnp_inited __initdata = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008219
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008220static PortAddr __init AscSearchIOPortAddr(PortAddr iop_beg, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008221{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008222 if (bus_type & ASC_IS_VL) {
8223 while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
8224 if (AscGetChipVersion(iop_beg, bus_type) <=
8225 ASC_CHIP_MAX_VER_VL) {
8226 return (iop_beg);
8227 }
8228 }
8229 return (0);
8230 }
8231 if (bus_type & ASC_IS_ISA) {
8232 if (_isa_pnp_inited == 0) {
8233 AscSetISAPNPWaitForKey();
8234 _isa_pnp_inited++;
8235 }
8236 while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
8237 if ((AscGetChipVersion(iop_beg, bus_type) &
8238 ASC_CHIP_VER_ISA_BIT) != 0) {
8239 return (iop_beg);
8240 }
8241 }
8242 return (0);
8243 }
8244 if (bus_type & ASC_IS_EISA) {
8245 if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
8246 return (iop_beg);
8247 }
8248 return (0);
8249 }
8250 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008251}
8252
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008253static PortAddr __init AscSearchIOPortAddr11(PortAddr s_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008254{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008255 int i;
8256 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008257
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008258 for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
8259 if (_asc_def_iop_base[i] > s_addr) {
8260 break;
8261 }
8262 }
8263 for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
8264 iop_base = _asc_def_iop_base[i];
8265 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
8266 ASC_DBG1(1,
8267 "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
8268 iop_base);
8269 continue;
8270 }
8271 ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n",
8272 iop_base);
8273 release_region(iop_base, ASC_IOADR_GAP);
8274 if (AscFindSignature(iop_base)) {
8275 return (iop_base);
8276 }
8277 }
8278 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008279}
8280
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008281static void __init AscSetISAPNPWaitForKey(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008282{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008283 outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
8284 outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
8285 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008286}
8287#endif /* CONFIG_ISA */
8288
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008289static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008290{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008291 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
8292 AscSetChipStatus(iop_base, 0);
8293 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008294}
8295
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008296static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008297{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008298 ushort cfg_lsw;
8299 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008300
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008301 if ((bus_type & ASC_IS_EISA) != 0) {
8302 cfg_lsw = AscGetEisaChipCfg(iop_base);
8303 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8304 if ((chip_irq == 13) || (chip_irq > 15)) {
8305 return (0);
8306 }
8307 return (chip_irq);
8308 }
8309 if ((bus_type & ASC_IS_VL) != 0) {
8310 cfg_lsw = AscGetChipCfgLsw(iop_base);
8311 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8312 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8313 return (0);
8314 }
8315 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8316 }
8317 cfg_lsw = AscGetChipCfgLsw(iop_base);
8318 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8319 if (chip_irq == 3)
8320 chip_irq += (uchar)2;
8321 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008322}
8323
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008324static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008325AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008326{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008327 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008328
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008329 if ((bus_type & ASC_IS_VL) != 0) {
8330 if (irq_no != 0) {
8331 if ((irq_no < ASC_MIN_IRQ_NO)
8332 || (irq_no > ASC_MAX_IRQ_NO)) {
8333 irq_no = 0;
8334 } else {
8335 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8336 }
8337 }
8338 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8339 cfg_lsw |= (ushort)0x0010;
8340 AscSetChipCfgLsw(iop_base, cfg_lsw);
8341 AscToggleIRQAct(iop_base);
8342 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8343 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8344 AscSetChipCfgLsw(iop_base, cfg_lsw);
8345 AscToggleIRQAct(iop_base);
8346 return (AscGetChipIRQ(iop_base, bus_type));
8347 }
8348 if ((bus_type & (ASC_IS_ISA)) != 0) {
8349 if (irq_no == 15)
8350 irq_no -= (uchar)2;
8351 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8352 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8353 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8354 AscSetChipCfgLsw(iop_base, cfg_lsw);
8355 return (AscGetChipIRQ(iop_base, bus_type));
8356 }
8357 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008358}
8359
8360#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008361static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008362{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008363 if (dma_channel < 4) {
8364 outp(0x000B, (ushort)(0xC0 | dma_channel));
8365 outp(0x000A, dma_channel);
8366 } else if (dma_channel < 8) {
8367 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8368 outp(0x00D4, (ushort)(dma_channel - 4));
8369 }
8370 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008371}
8372#endif /* CONFIG_ISA */
8373
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008374static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008375{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008376 EXT_MSG ext_msg;
8377 EXT_MSG out_msg;
8378 ushort halt_q_addr;
8379 int sdtr_accept;
8380 ushort int_halt_code;
8381 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8382 ASC_SCSI_BIT_ID_TYPE target_id;
8383 PortAddr iop_base;
8384 uchar tag_code;
8385 uchar q_status;
8386 uchar halt_qp;
8387 uchar sdtr_data;
8388 uchar target_ix;
8389 uchar q_cntl, tid_no;
8390 uchar cur_dvc_qng;
8391 uchar asyn_sdtr;
8392 uchar scsi_status;
8393 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008394
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008395 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8396 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008397
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008398 iop_base = asc_dvc->iop_base;
8399 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008400
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008401 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8402 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8403 target_ix = AscReadLramByte(iop_base,
8404 (ushort)(halt_q_addr +
8405 (ushort)ASC_SCSIQ_B_TARGET_IX));
8406 q_cntl =
8407 AscReadLramByte(iop_base,
8408 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8409 tid_no = ASC_TIX_TO_TID(target_ix);
8410 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8411 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8412 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8413 } else {
8414 asyn_sdtr = 0;
8415 }
8416 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8417 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8418 AscSetChipSDTR(iop_base, 0, tid_no);
8419 boardp->sdtr_data[tid_no] = 0;
8420 }
8421 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8422 return (0);
8423 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8424 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8425 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8426 boardp->sdtr_data[tid_no] = asyn_sdtr;
8427 }
8428 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8429 return (0);
8430 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008431
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008432 AscMemWordCopyPtrFromLram(iop_base,
8433 ASCV_MSGIN_BEG,
8434 (uchar *)&ext_msg,
8435 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008436
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008437 if (ext_msg.msg_type == MS_EXTEND &&
8438 ext_msg.msg_req == MS_SDTR_CODE &&
8439 ext_msg.msg_len == MS_SDTR_LEN) {
8440 sdtr_accept = TRUE;
8441 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008443 sdtr_accept = FALSE;
8444 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8445 }
8446 if ((ext_msg.xfer_period <
8447 asc_dvc->sdtr_period_tbl[asc_dvc->
8448 host_init_sdtr_index])
8449 || (ext_msg.xfer_period >
8450 asc_dvc->sdtr_period_tbl[asc_dvc->
8451 max_sdtr_index])) {
8452 sdtr_accept = FALSE;
8453 ext_msg.xfer_period =
8454 asc_dvc->sdtr_period_tbl[asc_dvc->
8455 host_init_sdtr_index];
8456 }
8457 if (sdtr_accept) {
8458 sdtr_data =
8459 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8460 ext_msg.req_ack_offset);
8461 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008462
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008463 q_cntl |= QC_MSG_OUT;
8464 asc_dvc->init_sdtr &= ~target_id;
8465 asc_dvc->sdtr_done &= ~target_id;
8466 AscSetChipSDTR(iop_base, asyn_sdtr,
8467 tid_no);
8468 boardp->sdtr_data[tid_no] = asyn_sdtr;
8469 }
8470 }
8471 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008472
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008473 q_cntl &= ~QC_MSG_OUT;
8474 asc_dvc->init_sdtr &= ~target_id;
8475 asc_dvc->sdtr_done &= ~target_id;
8476 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8477 } else {
8478 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008479
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008480 q_cntl &= ~QC_MSG_OUT;
8481 asc_dvc->sdtr_done |= target_id;
8482 asc_dvc->init_sdtr |= target_id;
8483 asc_dvc->pci_fix_asyn_xfer &=
8484 ~target_id;
8485 sdtr_data =
8486 AscCalSDTRData(asc_dvc,
8487 ext_msg.xfer_period,
8488 ext_msg.
8489 req_ack_offset);
8490 AscSetChipSDTR(iop_base, sdtr_data,
8491 tid_no);
8492 boardp->sdtr_data[tid_no] = sdtr_data;
8493 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008494
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008495 q_cntl |= QC_MSG_OUT;
8496 AscMsgOutSDTR(asc_dvc,
8497 ext_msg.xfer_period,
8498 ext_msg.req_ack_offset);
8499 asc_dvc->pci_fix_asyn_xfer &=
8500 ~target_id;
8501 sdtr_data =
8502 AscCalSDTRData(asc_dvc,
8503 ext_msg.xfer_period,
8504 ext_msg.
8505 req_ack_offset);
8506 AscSetChipSDTR(iop_base, sdtr_data,
8507 tid_no);
8508 boardp->sdtr_data[tid_no] = sdtr_data;
8509 asc_dvc->sdtr_done |= target_id;
8510 asc_dvc->init_sdtr |= target_id;
8511 }
8512 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008513
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008514 AscWriteLramByte(iop_base,
8515 (ushort)(halt_q_addr +
8516 (ushort)ASC_SCSIQ_B_CNTL),
8517 q_cntl);
8518 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8519 return (0);
8520 } else if (ext_msg.msg_type == MS_EXTEND &&
8521 ext_msg.msg_req == MS_WDTR_CODE &&
8522 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008523
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008524 ext_msg.wdtr_width = 0;
8525 AscMemWordCopyPtrToLram(iop_base,
8526 ASCV_MSGOUT_BEG,
8527 (uchar *)&ext_msg,
8528 sizeof(EXT_MSG) >> 1);
8529 q_cntl |= QC_MSG_OUT;
8530 AscWriteLramByte(iop_base,
8531 (ushort)(halt_q_addr +
8532 (ushort)ASC_SCSIQ_B_CNTL),
8533 q_cntl);
8534 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8535 return (0);
8536 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008537
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008538 ext_msg.msg_type = MESSAGE_REJECT;
8539 AscMemWordCopyPtrToLram(iop_base,
8540 ASCV_MSGOUT_BEG,
8541 (uchar *)&ext_msg,
8542 sizeof(EXT_MSG) >> 1);
8543 q_cntl |= QC_MSG_OUT;
8544 AscWriteLramByte(iop_base,
8545 (ushort)(halt_q_addr +
8546 (ushort)ASC_SCSIQ_B_CNTL),
8547 q_cntl);
8548 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8549 return (0);
8550 }
8551 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008553 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008554
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008555 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008556
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008557 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008558
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008559 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8560 q_cntl |= QC_MSG_OUT;
8561 AscMsgOutSDTR(asc_dvc,
8562 asc_dvc->
8563 sdtr_period_tbl[(sdtr_data >> 4) &
8564 (uchar)(asc_dvc->
8565 max_sdtr_index -
8566 1)],
8567 (uchar)(sdtr_data & (uchar)
8568 ASC_SYN_MAX_OFFSET));
8569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008570
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008571 AscWriteLramByte(iop_base,
8572 (ushort)(halt_q_addr +
8573 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008574
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008575 tag_code = AscReadLramByte(iop_base,
8576 (ushort)(halt_q_addr + (ushort)
8577 ASC_SCSIQ_B_TAG_CODE));
8578 tag_code &= 0xDC;
8579 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8580 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8581 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008582
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008583 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8584 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008585
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008586 }
8587 AscWriteLramByte(iop_base,
8588 (ushort)(halt_q_addr +
8589 (ushort)ASC_SCSIQ_B_TAG_CODE),
8590 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008592 q_status = AscReadLramByte(iop_base,
8593 (ushort)(halt_q_addr + (ushort)
8594 ASC_SCSIQ_B_STATUS));
8595 q_status |= (QS_READY | QS_BUSY);
8596 AscWriteLramByte(iop_base,
8597 (ushort)(halt_q_addr +
8598 (ushort)ASC_SCSIQ_B_STATUS),
8599 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008600
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008601 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8602 scsi_busy &= ~target_id;
8603 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008604
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008605 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8606 return (0);
8607 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008608
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008609 AscMemWordCopyPtrFromLram(iop_base,
8610 ASCV_MSGOUT_BEG,
8611 (uchar *)&out_msg,
8612 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008613
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008614 if ((out_msg.msg_type == MS_EXTEND) &&
8615 (out_msg.msg_len == MS_SDTR_LEN) &&
8616 (out_msg.msg_req == MS_SDTR_CODE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008617
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008618 asc_dvc->init_sdtr &= ~target_id;
8619 asc_dvc->sdtr_done &= ~target_id;
8620 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8621 boardp->sdtr_data[tid_no] = asyn_sdtr;
8622 }
8623 q_cntl &= ~QC_MSG_OUT;
8624 AscWriteLramByte(iop_base,
8625 (ushort)(halt_q_addr +
8626 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8627 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8628 return (0);
8629 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008630
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008631 scsi_status = AscReadLramByte(iop_base,
8632 (ushort)((ushort)halt_q_addr +
8633 (ushort)
8634 ASC_SCSIQ_SCSI_STATUS));
8635 cur_dvc_qng =
8636 AscReadLramByte(iop_base,
8637 (ushort)((ushort)ASC_QADR_BEG +
8638 (ushort)target_ix));
8639 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008641 scsi_busy = AscReadLramByte(iop_base,
8642 (ushort)ASCV_SCSIBUSY_B);
8643 scsi_busy |= target_id;
8644 AscWriteLramByte(iop_base,
8645 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8646 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008647
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008648 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8649 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8650 cur_dvc_qng -= 1;
8651 asc_dvc->max_dvc_qng[tid_no] =
8652 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008653
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008654 AscWriteLramByte(iop_base,
8655 (ushort)((ushort)
8656 ASCV_MAX_DVC_QNG_BEG
8657 + (ushort)
8658 tid_no),
8659 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008660
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008661 /*
8662 * Set the device queue depth to the number of
8663 * active requests when the QUEUE FULL condition
8664 * was encountered.
8665 */
8666 boardp->queue_full |= target_id;
8667 boardp->queue_full_cnt[tid_no] =
8668 cur_dvc_qng;
8669 }
8670 }
8671 }
8672 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8673 return (0);
8674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008675#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008676 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8677 uchar q_no;
8678 ushort q_addr;
8679 uchar sg_wk_q_no;
8680 uchar first_sg_wk_q_no;
8681 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8682 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8683 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8684 ushort sg_list_dwords;
8685 ushort sg_entry_cnt;
8686 uchar next_qp;
8687 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008688
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008689 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8690 if (q_no == ASC_QLINK_END) {
8691 return (0);
8692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008693
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008694 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008695
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008696 /*
8697 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8698 * structure pointer using a macro provided by the driver.
8699 * The ASC_SCSI_REQ pointer provides a pointer to the
8700 * host ASC_SG_HEAD structure.
8701 */
8702 /* Read request's SRB pointer. */
8703 scsiq = (ASC_SCSI_Q *)
8704 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8705 (ushort)
8706 (q_addr +
8707 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008708
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008709 /*
8710 * Get request's first and working SG queue.
8711 */
8712 sg_wk_q_no = AscReadLramByte(iop_base,
8713 (ushort)(q_addr +
8714 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008715
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008716 first_sg_wk_q_no = AscReadLramByte(iop_base,
8717 (ushort)(q_addr +
8718 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008719
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008720 /*
8721 * Reset request's working SG queue back to the
8722 * first SG queue.
8723 */
8724 AscWriteLramByte(iop_base,
8725 (ushort)(q_addr +
8726 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8727 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008728
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008729 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008730
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008731 /*
8732 * Set sg_entry_cnt to the number of SG elements
8733 * that will be completed on this interrupt.
8734 *
8735 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8736 * SG elements. The data_cnt and data_addr fields which
8737 * add 1 to the SG element capacity are not used when
8738 * restarting SG handling after a halt.
8739 */
8740 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8741 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008743 /*
8744 * Keep track of remaining number of SG elements that will
8745 * need to be handled on the next interrupt.
8746 */
8747 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8748 } else {
8749 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8750 scsiq->remain_sg_entry_cnt = 0;
8751 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008752
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008753 /*
8754 * Copy SG elements into the list of allocated SG queues.
8755 *
8756 * Last index completed is saved in scsiq->next_sg_index.
8757 */
8758 next_qp = first_sg_wk_q_no;
8759 q_addr = ASC_QNO_TO_QADDR(next_qp);
8760 scsi_sg_q.sg_head_qp = q_no;
8761 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8762 for (i = 0; i < sg_head->queue_cnt; i++) {
8763 scsi_sg_q.seq_no = i + 1;
8764 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8765 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8766 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8767 /*
8768 * After very first SG queue RISC FW uses next
8769 * SG queue first element then checks sg_list_cnt
8770 * against zero and then decrements, so set
8771 * sg_list_cnt 1 less than number of SG elements
8772 * in each SG queue.
8773 */
8774 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8775 scsi_sg_q.sg_cur_list_cnt =
8776 ASC_SG_LIST_PER_Q - 1;
8777 } else {
8778 /*
8779 * This is the last SG queue in the list of
8780 * allocated SG queues. If there are more
8781 * SG elements than will fit in the allocated
8782 * queues, then set the QCSG_SG_XFER_MORE flag.
8783 */
8784 if (scsiq->remain_sg_entry_cnt != 0) {
8785 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8786 } else {
8787 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8788 }
8789 /* equals sg_entry_cnt * 2 */
8790 sg_list_dwords = sg_entry_cnt << 1;
8791 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8792 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8793 sg_entry_cnt = 0;
8794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008796 scsi_sg_q.q_no = next_qp;
8797 AscMemWordCopyPtrToLram(iop_base,
8798 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8799 (uchar *)&scsi_sg_q,
8800 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008801
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008802 AscMemDWordCopyPtrToLram(iop_base,
8803 q_addr + ASC_SGQ_LIST_BEG,
8804 (uchar *)&sg_head->
8805 sg_list[scsiq->next_sg_index],
8806 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008807
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008808 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008810 /*
8811 * If the just completed SG queue contained the
8812 * last SG element, then no more SG queues need
8813 * to be written.
8814 */
8815 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8816 break;
8817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008818
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008819 next_qp = AscReadLramByte(iop_base,
8820 (ushort)(q_addr +
8821 ASC_SCSIQ_B_FWD));
8822 q_addr = ASC_QNO_TO_QADDR(next_qp);
8823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008824
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008825 /*
8826 * Clear the halt condition so the RISC will be restarted
8827 * after the return.
8828 */
8829 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8830 return (0);
8831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008832#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008833 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008834}
8835
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008836static uchar
8837_AscCopyLramScsiDoneQ(PortAddr iop_base,
8838 ushort q_addr,
8839 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008840{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008841 ushort _val;
8842 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008843
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008844 DvcGetQinfo(iop_base,
8845 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8846 (uchar *)scsiq,
8847 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008848
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008849 _val = AscReadLramWord(iop_base,
8850 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8851 scsiq->q_status = (uchar)_val;
8852 scsiq->q_no = (uchar)(_val >> 8);
8853 _val = AscReadLramWord(iop_base,
8854 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8855 scsiq->cntl = (uchar)_val;
8856 sg_queue_cnt = (uchar)(_val >> 8);
8857 _val = AscReadLramWord(iop_base,
8858 (ushort)(q_addr +
8859 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8860 scsiq->sense_len = (uchar)_val;
8861 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008862
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008863 /*
8864 * Read high word of remain bytes from alternate location.
8865 */
8866 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
8867 (ushort)(q_addr +
8868 (ushort)
8869 ASC_SCSIQ_W_ALT_DC1)))
8870 << 16);
8871 /*
8872 * Read low word of remain bytes from original location.
8873 */
8874 scsiq->remain_bytes += AscReadLramWord(iop_base,
8875 (ushort)(q_addr + (ushort)
8876 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008877
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008878 scsiq->remain_bytes &= max_dma_count;
8879 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008880}
8881
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008882static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008883{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008884 uchar next_qp;
8885 uchar n_q_used;
8886 uchar sg_list_qp;
8887 uchar sg_queue_cnt;
8888 uchar q_cnt;
8889 uchar done_q_tail;
8890 uchar tid_no;
8891 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8892 ASC_SCSI_BIT_ID_TYPE target_id;
8893 PortAddr iop_base;
8894 ushort q_addr;
8895 ushort sg_q_addr;
8896 uchar cur_target_qng;
8897 ASC_QDONE_INFO scsiq_buf;
8898 ASC_QDONE_INFO *scsiq;
8899 int false_overrun;
8900 ASC_ISR_CALLBACK asc_isr_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008901
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008902 iop_base = asc_dvc->iop_base;
8903 asc_isr_callback = asc_dvc->isr_callback;
8904 n_q_used = 1;
8905 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
8906 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
8907 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
8908 next_qp = AscReadLramByte(iop_base,
8909 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
8910 if (next_qp != ASC_QLINK_END) {
8911 AscPutVarDoneQTail(iop_base, next_qp);
8912 q_addr = ASC_QNO_TO_QADDR(next_qp);
8913 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
8914 asc_dvc->max_dma_count);
8915 AscWriteLramByte(iop_base,
8916 (ushort)(q_addr +
8917 (ushort)ASC_SCSIQ_B_STATUS),
8918 (uchar)(scsiq->
8919 q_status & (uchar)~(QS_READY |
8920 QS_ABORTED)));
8921 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
8922 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
8923 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
8924 sg_q_addr = q_addr;
8925 sg_list_qp = next_qp;
8926 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
8927 sg_list_qp = AscReadLramByte(iop_base,
8928 (ushort)(sg_q_addr
8929 + (ushort)
8930 ASC_SCSIQ_B_FWD));
8931 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
8932 if (sg_list_qp == ASC_QLINK_END) {
8933 AscSetLibErrorCode(asc_dvc,
8934 ASCQ_ERR_SG_Q_LINKS);
8935 scsiq->d3.done_stat = QD_WITH_ERROR;
8936 scsiq->d3.host_stat =
8937 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
8938 goto FATAL_ERR_QDONE;
8939 }
8940 AscWriteLramByte(iop_base,
8941 (ushort)(sg_q_addr + (ushort)
8942 ASC_SCSIQ_B_STATUS),
8943 QS_FREE);
8944 }
8945 n_q_used = sg_queue_cnt + 1;
8946 AscPutVarDoneQTail(iop_base, sg_list_qp);
8947 }
8948 if (asc_dvc->queue_full_or_busy & target_id) {
8949 cur_target_qng = AscReadLramByte(iop_base,
8950 (ushort)((ushort)
8951 ASC_QADR_BEG
8952 + (ushort)
8953 scsiq->d2.
8954 target_ix));
8955 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
8956 scsi_busy = AscReadLramByte(iop_base, (ushort)
8957 ASCV_SCSIBUSY_B);
8958 scsi_busy &= ~target_id;
8959 AscWriteLramByte(iop_base,
8960 (ushort)ASCV_SCSIBUSY_B,
8961 scsi_busy);
8962 asc_dvc->queue_full_or_busy &= ~target_id;
8963 }
8964 }
8965 if (asc_dvc->cur_total_qng >= n_q_used) {
8966 asc_dvc->cur_total_qng -= n_q_used;
8967 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
8968 asc_dvc->cur_dvc_qng[tid_no]--;
8969 }
8970 } else {
8971 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
8972 scsiq->d3.done_stat = QD_WITH_ERROR;
8973 goto FATAL_ERR_QDONE;
8974 }
8975 if ((scsiq->d2.srb_ptr == 0UL) ||
8976 ((scsiq->q_status & QS_ABORTED) != 0)) {
8977 return (0x11);
8978 } else if (scsiq->q_status == QS_DONE) {
8979 false_overrun = FALSE;
8980 if (scsiq->extra_bytes != 0) {
8981 scsiq->remain_bytes +=
8982 (ADV_DCNT)scsiq->extra_bytes;
8983 }
8984 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
8985 if (scsiq->d3.host_stat ==
8986 QHSTA_M_DATA_OVER_RUN) {
8987 if ((scsiq->
8988 cntl & (QC_DATA_IN | QC_DATA_OUT))
8989 == 0) {
8990 scsiq->d3.done_stat =
8991 QD_NO_ERROR;
8992 scsiq->d3.host_stat =
8993 QHSTA_NO_ERROR;
8994 } else if (false_overrun) {
8995 scsiq->d3.done_stat =
8996 QD_NO_ERROR;
8997 scsiq->d3.host_stat =
8998 QHSTA_NO_ERROR;
8999 }
9000 } else if (scsiq->d3.host_stat ==
9001 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
9002 AscStopChip(iop_base);
9003 AscSetChipControl(iop_base,
9004 (uchar)(CC_SCSI_RESET
9005 | CC_HALT));
9006 DvcDelayNanoSecond(asc_dvc, 60000);
9007 AscSetChipControl(iop_base, CC_HALT);
9008 AscSetChipStatus(iop_base,
9009 CIW_CLR_SCSI_RESET_INT);
9010 AscSetChipStatus(iop_base, 0);
9011 AscSetChipControl(iop_base, 0);
9012 }
9013 }
9014 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
9015 (*asc_isr_callback) (asc_dvc, scsiq);
9016 } else {
9017 if ((AscReadLramByte(iop_base,
9018 (ushort)(q_addr + (ushort)
9019 ASC_SCSIQ_CDB_BEG))
9020 == START_STOP)) {
9021 asc_dvc->unit_not_ready &= ~target_id;
9022 if (scsiq->d3.done_stat != QD_NO_ERROR) {
9023 asc_dvc->start_motor &=
9024 ~target_id;
9025 }
9026 }
9027 }
9028 return (1);
9029 } else {
9030 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
9031 FATAL_ERR_QDONE:
9032 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
9033 (*asc_isr_callback) (asc_dvc, scsiq);
9034 }
9035 return (0x80);
9036 }
9037 }
9038 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009039}
9040
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009041static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009042{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009043 ASC_CS_TYPE chipstat;
9044 PortAddr iop_base;
9045 ushort saved_ram_addr;
9046 uchar ctrl_reg;
9047 uchar saved_ctrl_reg;
9048 int int_pending;
9049 int status;
9050 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009051
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009052 iop_base = asc_dvc->iop_base;
9053 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009054
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009055 if (AscIsIntPending(iop_base) == 0) {
9056 return int_pending;
9057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009058
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009059 if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
9060 || (asc_dvc->isr_callback == 0)
9061 ) {
9062 return (ERR);
9063 }
9064 if (asc_dvc->in_critical_cnt != 0) {
9065 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
9066 return (ERR);
9067 }
9068 if (asc_dvc->is_in_int) {
9069 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
9070 return (ERR);
9071 }
9072 asc_dvc->is_in_int = TRUE;
9073 ctrl_reg = AscGetChipControl(iop_base);
9074 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
9075 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
9076 chipstat = AscGetChipStatus(iop_base);
9077 if (chipstat & CSW_SCSI_RESET_LATCH) {
9078 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
9079 int i = 10;
9080 int_pending = TRUE;
9081 asc_dvc->sdtr_done = 0;
9082 saved_ctrl_reg &= (uchar)(~CC_HALT);
9083 while ((AscGetChipStatus(iop_base) &
9084 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
9085 DvcSleepMilliSecond(100);
9086 }
9087 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
9088 AscSetChipControl(iop_base, CC_HALT);
9089 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
9090 AscSetChipStatus(iop_base, 0);
9091 chipstat = AscGetChipStatus(iop_base);
9092 }
9093 }
9094 saved_ram_addr = AscGetChipLramAddr(iop_base);
9095 host_flag = AscReadLramByte(iop_base,
9096 ASCV_HOST_FLAG_B) &
9097 (uchar)(~ASC_HOST_FLAG_IN_ISR);
9098 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
9099 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
9100 if ((chipstat & CSW_INT_PENDING)
9101 || (int_pending)
9102 ) {
9103 AscAckInterrupt(iop_base);
9104 int_pending = TRUE;
9105 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
9106 if (AscIsrChipHalted(asc_dvc) == ERR) {
9107 goto ISR_REPORT_QDONE_FATAL_ERROR;
9108 } else {
9109 saved_ctrl_reg &= (uchar)(~CC_HALT);
9110 }
9111 } else {
9112 ISR_REPORT_QDONE_FATAL_ERROR:
9113 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
9114 while (((status =
9115 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
9116 }
9117 } else {
9118 do {
9119 if ((status =
9120 AscIsrQDone(asc_dvc)) == 1) {
9121 break;
9122 }
9123 } while (status == 0x11);
9124 }
9125 if ((status & 0x80) != 0)
9126 int_pending = ERR;
9127 }
9128 }
9129 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
9130 AscSetChipLramAddr(iop_base, saved_ram_addr);
9131 AscSetChipControl(iop_base, saved_ctrl_reg);
9132 asc_dvc->is_in_int = FALSE;
9133 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009134}
9135
9136/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009137static uchar _asc_mcode_buf[] = {
9138 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9139 0x00, 0x00, 0x00, 0x00,
9140 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
9141 0x00, 0x00, 0x00, 0x00,
9142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9143 0x00, 0x00, 0x00, 0x00,
9144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9145 0x00, 0x00, 0x00, 0x00,
9146 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
9147 0x00, 0xFF, 0x00, 0x00,
9148 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
9149 0x00, 0x00, 0x00, 0x00,
9150 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
9151 0x00, 0x00, 0x00, 0x00,
9152 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
9153 0x00, 0x00, 0x00, 0x00,
9154 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
9155 0x03, 0x23, 0x36, 0x40,
9156 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
9157 0xC2, 0x00, 0x92, 0x80,
9158 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
9159 0xB6, 0x00, 0x92, 0x80,
9160 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
9161 0x92, 0x80, 0x80, 0x62,
9162 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
9163 0xCD, 0x04, 0x4D, 0x00,
9164 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
9165 0xE6, 0x84, 0xD2, 0xC1,
9166 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
9167 0xC6, 0x81, 0xC2, 0x88,
9168 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
9169 0x84, 0x97, 0x07, 0xA6,
9170 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
9171 0xC2, 0x88, 0xCE, 0x00,
9172 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
9173 0x80, 0x63, 0x07, 0xA6,
9174 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
9175 0x34, 0x01, 0x00, 0x33,
9176 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
9177 0x68, 0x98, 0x4D, 0x04,
9178 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
9179 0xF8, 0x88, 0xFB, 0x23,
9180 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
9181 0x00, 0x33, 0x0A, 0x00,
9182 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
9183 0xC2, 0x88, 0xCD, 0x04,
9184 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
9185 0x06, 0xAB, 0x82, 0x01,
9186 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
9187 0x3C, 0x01, 0x00, 0x05,
9188 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
9189 0x15, 0x23, 0xA1, 0x01,
9190 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
9191 0x06, 0x61, 0x00, 0xA0,
9192 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
9193 0xC2, 0x88, 0x06, 0x23,
9194 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
9195 0x57, 0x60, 0x00, 0xA0,
9196 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
9197 0x4B, 0x00, 0x06, 0x61,
9198 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
9199 0x4F, 0x00, 0x84, 0x97,
9200 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
9201 0x48, 0x04, 0x84, 0x80,
9202 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
9203 0x81, 0x73, 0x06, 0x29,
9204 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
9205 0x04, 0x98, 0xF0, 0x80,
9206 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
9207 0x34, 0x02, 0x03, 0xA6,
9208 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
9209 0x46, 0x82, 0xFE, 0x95,
9210 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
9211 0x07, 0xA6, 0x5A, 0x02,
9212 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
9213 0x48, 0x82, 0x60, 0x96,
9214 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
9215 0x04, 0x01, 0x0C, 0xDC,
9216 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
9217 0x6F, 0x00, 0xA5, 0x01,
9218 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
9219 0x02, 0xA6, 0xAA, 0x02,
9220 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
9221 0x01, 0xA6, 0xB4, 0x02,
9222 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
9223 0x80, 0x63, 0x00, 0x43,
9224 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
9225 0x04, 0x61, 0x84, 0x01,
9226 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
9227 0x00, 0x00, 0xEA, 0x82,
9228 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
9229 0x00, 0x33, 0x1F, 0x00,
9230 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
9231 0xB6, 0x2D, 0x01, 0xA6,
9232 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
9233 0x10, 0x03, 0x03, 0xA6,
9234 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
9235 0x7C, 0x95, 0xEE, 0x82,
9236 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
9237 0x04, 0x01, 0x2D, 0xC8,
9238 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
9239 0x05, 0x05, 0x86, 0x98,
9240 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
9241 0x3C, 0x04, 0x06, 0xA6,
9242 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
9243 0x7C, 0x95, 0x32, 0x83,
9244 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
9245 0xEB, 0x04, 0x00, 0x33,
9246 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
9247 0xFF, 0xA2, 0x7A, 0x03,
9248 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
9249 0x00, 0xA2, 0x9A, 0x03,
9250 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
9251 0x01, 0xA6, 0x96, 0x03,
9252 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
9253 0xA4, 0x03, 0x00, 0xA6,
9254 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
9255 0x07, 0xA6, 0xB2, 0x03,
9256 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
9257 0xA8, 0x98, 0x80, 0x42,
9258 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
9259 0xC0, 0x83, 0x00, 0x33,
9260 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
9261 0xA0, 0x01, 0x12, 0x23,
9262 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
9263 0x80, 0x67, 0x05, 0x23,
9264 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
9265 0x06, 0xA6, 0x0A, 0x04,
9266 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
9267 0xF4, 0x83, 0x20, 0x84,
9268 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
9269 0x83, 0x03, 0x80, 0x63,
9270 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
9271 0x38, 0x04, 0x00, 0x33,
9272 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
9273 0x1D, 0x01, 0x06, 0xCC,
9274 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
9275 0xA2, 0x0D, 0x80, 0x63,
9276 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
9277 0x80, 0x63, 0xA3, 0x01,
9278 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
9279 0x76, 0x04, 0xE0, 0x00,
9280 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
9281 0x00, 0x33, 0x1E, 0x00,
9282 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
9283 0x08, 0x23, 0x22, 0xA3,
9284 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
9285 0xC4, 0x04, 0x42, 0x23,
9286 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
9287 0xF8, 0x88, 0x04, 0x98,
9288 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
9289 0x81, 0x62, 0xE8, 0x81,
9290 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
9291 0x00, 0x33, 0x00, 0x81,
9292 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
9293 0xF8, 0x88, 0x04, 0x23,
9294 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
9295 0xF4, 0x04, 0x00, 0x33,
9296 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9297 0x04, 0x23, 0xA0, 0x01,
9298 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9299 0x00, 0xA3, 0x22, 0x05,
9300 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9301 0x46, 0x97, 0xCD, 0x04,
9302 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9303 0x82, 0x01, 0x34, 0x85,
9304 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9305 0x1D, 0x01, 0x04, 0xD6,
9306 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9307 0x49, 0x00, 0x81, 0x01,
9308 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9309 0x49, 0x04, 0x80, 0x01,
9310 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9311 0x01, 0x23, 0xEA, 0x00,
9312 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9313 0x07, 0xA4, 0xF8, 0x05,
9314 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9315 0xC2, 0x88, 0x04, 0xA0,
9316 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9317 0x00, 0xA2, 0xA4, 0x05,
9318 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9319 0x62, 0x97, 0x04, 0x85,
9320 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9321 0xF4, 0x85, 0x03, 0xA0,
9322 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9323 0xCC, 0x86, 0x07, 0xA0,
9324 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9325 0x80, 0x67, 0x80, 0x63,
9326 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9327 0xF8, 0x88, 0x07, 0x23,
9328 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9329 0x00, 0x63, 0x4A, 0x00,
9330 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9331 0x07, 0x41, 0x83, 0x03,
9332 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9333 0x1D, 0x01, 0x01, 0xD6,
9334 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9335 0x07, 0xA6, 0x7C, 0x05,
9336 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9337 0x52, 0x00, 0x06, 0x61,
9338 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9339 0x00, 0x63, 0x1D, 0x01,
9340 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9341 0x07, 0x41, 0x00, 0x63,
9342 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9343 0xDF, 0x00, 0x06, 0xA6,
9344 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9345 0x00, 0x40, 0xC0, 0x20,
9346 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9347 0x06, 0xA6, 0x94, 0x06,
9348 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9349 0x40, 0x0E, 0x80, 0x63,
9350 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9351 0x80, 0x63, 0x00, 0x43,
9352 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9353 0x80, 0x67, 0x40, 0x0E,
9354 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9355 0x07, 0xA6, 0xD6, 0x06,
9356 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9357 0x0A, 0x2B, 0x07, 0xA6,
9358 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9359 0xF4, 0x06, 0xC0, 0x0E,
9360 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9361 0x81, 0x62, 0x04, 0x01,
9362 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9363 0x8C, 0x06, 0x00, 0x33,
9364 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9365 0x80, 0x63, 0x06, 0xA6,
9366 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9367 0x00, 0x00, 0x80, 0x67,
9368 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9369 0xBF, 0x23, 0x04, 0x61,
9370 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9371 0x00, 0x01, 0xF2, 0x00,
9372 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9373 0x80, 0x05, 0x81, 0x05,
9374 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9375 0x70, 0x00, 0x81, 0x01,
9376 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9377 0x70, 0x00, 0x80, 0x01,
9378 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9379 0xF1, 0x00, 0x70, 0x00,
9380 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9381 0x71, 0x04, 0x70, 0x00,
9382 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9383 0xA3, 0x01, 0xA2, 0x01,
9384 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9385 0xC4, 0x07, 0x00, 0x33,
9386 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9387 0x48, 0x00, 0xB0, 0x01,
9388 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9389 0x00, 0xA2, 0xE4, 0x07,
9390 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9391 0x05, 0x05, 0x00, 0x63,
9392 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9393 0x76, 0x08, 0x80, 0x02,
9394 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9395 0x00, 0x02, 0x00, 0xA0,
9396 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9397 0x00, 0x63, 0xF3, 0x04,
9398 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9399 0x00, 0xA2, 0x44, 0x08,
9400 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9401 0x24, 0x08, 0x04, 0x98,
9402 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9403 0x5A, 0x88, 0x02, 0x01,
9404 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9405 0x00, 0xA3, 0x64, 0x08,
9406 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9407 0x06, 0xA6, 0x76, 0x08,
9408 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9409 0x00, 0x63, 0x38, 0x2B,
9410 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9411 0x05, 0x05, 0xB2, 0x09,
9412 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9413 0x80, 0x32, 0x80, 0x36,
9414 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9415 0x40, 0x36, 0x40, 0x3A,
9416 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9417 0x5D, 0x00, 0xFE, 0xC3,
9418 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9419 0xFF, 0xFD, 0x80, 0x73,
9420 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9421 0xA1, 0x23, 0xA1, 0x01,
9422 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9423 0x80, 0x00, 0x03, 0xC2,
9424 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9425 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009426};
9427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009428static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9429static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009430
9431#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009432static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9433 INQUIRY,
9434 REQUEST_SENSE,
9435 READ_CAPACITY,
9436 READ_TOC,
9437 MODE_SELECT,
9438 MODE_SENSE,
9439 MODE_SELECT_10,
9440 MODE_SENSE_10,
9441 0xFF,
9442 0xFF,
9443 0xFF,
9444 0xFF,
9445 0xFF,
9446 0xFF,
9447 0xFF,
9448 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009449};
9450
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009451static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009452{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009453 PortAddr iop_base;
9454 ulong last_int_level;
9455 int sta;
9456 int n_q_required;
9457 int disable_syn_offset_one_fix;
9458 int i;
9459 ASC_PADDR addr;
9460 ASC_EXE_CALLBACK asc_exe_callback;
9461 ushort sg_entry_cnt = 0;
9462 ushort sg_entry_cnt_minus_one = 0;
9463 uchar target_ix;
9464 uchar tid_no;
9465 uchar sdtr_data;
9466 uchar extra_bytes;
9467 uchar scsi_cmd;
9468 uchar disable_cmd;
9469 ASC_SG_HEAD *sg_head;
9470 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009471
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009472 iop_base = asc_dvc->iop_base;
9473 sg_head = scsiq->sg_head;
9474 asc_exe_callback = asc_dvc->exe_callback;
9475 if (asc_dvc->err_code != 0)
9476 return (ERR);
9477 if (scsiq == (ASC_SCSI_Q *)0L) {
9478 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9479 return (ERR);
9480 }
9481 scsiq->q1.q_no = 0;
9482 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9483 scsiq->q1.extra_bytes = 0;
9484 }
9485 sta = 0;
9486 target_ix = scsiq->q2.target_ix;
9487 tid_no = ASC_TIX_TO_TID(target_ix);
9488 n_q_required = 1;
9489 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9490 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9491 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9492 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9493 AscMsgOutSDTR(asc_dvc,
9494 asc_dvc->
9495 sdtr_period_tbl[(sdtr_data >> 4) &
9496 (uchar)(asc_dvc->
9497 max_sdtr_index -
9498 1)],
9499 (uchar)(sdtr_data & (uchar)
9500 ASC_SYN_MAX_OFFSET));
9501 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9502 }
9503 }
9504 last_int_level = DvcEnterCritical();
9505 if (asc_dvc->in_critical_cnt != 0) {
9506 DvcLeaveCritical(last_int_level);
9507 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9508 return (ERR);
9509 }
9510 asc_dvc->in_critical_cnt++;
9511 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9512 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9513 asc_dvc->in_critical_cnt--;
9514 DvcLeaveCritical(last_int_level);
9515 return (ERR);
9516 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009517#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009518 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9519 asc_dvc->in_critical_cnt--;
9520 DvcLeaveCritical(last_int_level);
9521 return (ERR);
9522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009523#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009524 if (sg_entry_cnt == 1) {
9525 scsiq->q1.data_addr =
9526 (ADV_PADDR)sg_head->sg_list[0].addr;
9527 scsiq->q1.data_cnt =
9528 (ADV_DCNT)sg_head->sg_list[0].bytes;
9529 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9530 }
9531 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9532 }
9533 scsi_cmd = scsiq->cdbptr[0];
9534 disable_syn_offset_one_fix = FALSE;
9535 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9536 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9537 if (scsiq->q1.cntl & QC_SG_HEAD) {
9538 data_cnt = 0;
9539 for (i = 0; i < sg_entry_cnt; i++) {
9540 data_cnt +=
9541 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9542 bytes);
9543 }
9544 } else {
9545 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9546 }
9547 if (data_cnt != 0UL) {
9548 if (data_cnt < 512UL) {
9549 disable_syn_offset_one_fix = TRUE;
9550 } else {
9551 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9552 i++) {
9553 disable_cmd =
9554 _syn_offset_one_disable_cmd[i];
9555 if (disable_cmd == 0xFF) {
9556 break;
9557 }
9558 if (scsi_cmd == disable_cmd) {
9559 disable_syn_offset_one_fix =
9560 TRUE;
9561 break;
9562 }
9563 }
9564 }
9565 }
9566 }
9567 if (disable_syn_offset_one_fix) {
9568 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9569 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9570 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9571 } else {
9572 scsiq->q2.tag_code &= 0x27;
9573 }
9574 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9575 if (asc_dvc->bug_fix_cntl) {
9576 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9577 if ((scsi_cmd == READ_6) ||
9578 (scsi_cmd == READ_10)) {
9579 addr =
9580 (ADV_PADDR)le32_to_cpu(sg_head->
9581 sg_list
9582 [sg_entry_cnt_minus_one].
9583 addr) +
9584 (ADV_DCNT)le32_to_cpu(sg_head->
9585 sg_list
9586 [sg_entry_cnt_minus_one].
9587 bytes);
9588 extra_bytes =
9589 (uchar)((ushort)addr & 0x0003);
9590 if ((extra_bytes != 0)
9591 &&
9592 ((scsiq->q2.
9593 tag_code &
9594 ASC_TAG_FLAG_EXTRA_BYTES)
9595 == 0)) {
9596 scsiq->q2.tag_code |=
9597 ASC_TAG_FLAG_EXTRA_BYTES;
9598 scsiq->q1.extra_bytes =
9599 extra_bytes;
9600 data_cnt =
9601 le32_to_cpu(sg_head->
9602 sg_list
9603 [sg_entry_cnt_minus_one].
9604 bytes);
9605 data_cnt -=
9606 (ASC_DCNT) extra_bytes;
9607 sg_head->
9608 sg_list
9609 [sg_entry_cnt_minus_one].
9610 bytes =
9611 cpu_to_le32(data_cnt);
9612 }
9613 }
9614 }
9615 }
9616 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009617#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009618 /*
9619 * Set the sg_entry_cnt to the maximum possible. The rest of
9620 * the SG elements will be copied when the RISC completes the
9621 * SG elements that fit and halts.
9622 */
9623 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9624 sg_entry_cnt = ASC_MAX_SG_LIST;
9625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009626#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009627 n_q_required = AscSgListToQueue(sg_entry_cnt);
9628 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9629 (uint) n_q_required)
9630 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9631 if ((sta =
9632 AscSendScsiQueue(asc_dvc, scsiq,
9633 n_q_required)) == 1) {
9634 asc_dvc->in_critical_cnt--;
9635 if (asc_exe_callback != 0) {
9636 (*asc_exe_callback) (asc_dvc, scsiq);
9637 }
9638 DvcLeaveCritical(last_int_level);
9639 return (sta);
9640 }
9641 }
9642 } else {
9643 if (asc_dvc->bug_fix_cntl) {
9644 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9645 if ((scsi_cmd == READ_6) ||
9646 (scsi_cmd == READ_10)) {
9647 addr =
9648 le32_to_cpu(scsiq->q1.data_addr) +
9649 le32_to_cpu(scsiq->q1.data_cnt);
9650 extra_bytes =
9651 (uchar)((ushort)addr & 0x0003);
9652 if ((extra_bytes != 0)
9653 &&
9654 ((scsiq->q2.
9655 tag_code &
9656 ASC_TAG_FLAG_EXTRA_BYTES)
9657 == 0)) {
9658 data_cnt =
9659 le32_to_cpu(scsiq->q1.
9660 data_cnt);
9661 if (((ushort)data_cnt & 0x01FF)
9662 == 0) {
9663 scsiq->q2.tag_code |=
9664 ASC_TAG_FLAG_EXTRA_BYTES;
9665 data_cnt -= (ASC_DCNT)
9666 extra_bytes;
9667 scsiq->q1.data_cnt =
9668 cpu_to_le32
9669 (data_cnt);
9670 scsiq->q1.extra_bytes =
9671 extra_bytes;
9672 }
9673 }
9674 }
9675 }
9676 }
9677 n_q_required = 1;
9678 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9679 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9680 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9681 n_q_required)) == 1) {
9682 asc_dvc->in_critical_cnt--;
9683 if (asc_exe_callback != 0) {
9684 (*asc_exe_callback) (asc_dvc, scsiq);
9685 }
9686 DvcLeaveCritical(last_int_level);
9687 return (sta);
9688 }
9689 }
9690 }
9691 asc_dvc->in_critical_cnt--;
9692 DvcLeaveCritical(last_int_level);
9693 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009694}
9695
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009696static int
9697AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009698{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009699 PortAddr iop_base;
9700 uchar free_q_head;
9701 uchar next_qp;
9702 uchar tid_no;
9703 uchar target_ix;
9704 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009705
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009706 iop_base = asc_dvc->iop_base;
9707 target_ix = scsiq->q2.target_ix;
9708 tid_no = ASC_TIX_TO_TID(target_ix);
9709 sta = 0;
9710 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9711 if (n_q_required > 1) {
9712 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9713 free_q_head, (uchar)
9714 (n_q_required)))
9715 != (uchar)ASC_QLINK_END) {
9716 asc_dvc->last_q_shortage = 0;
9717 scsiq->sg_head->queue_cnt = n_q_required - 1;
9718 scsiq->q1.q_no = free_q_head;
9719 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9720 free_q_head)) == 1) {
9721 AscPutVarFreeQHead(iop_base, next_qp);
9722 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9723 asc_dvc->cur_dvc_qng[tid_no]++;
9724 }
9725 return (sta);
9726 }
9727 } else if (n_q_required == 1) {
9728 if ((next_qp = AscAllocFreeQueue(iop_base,
9729 free_q_head)) !=
9730 ASC_QLINK_END) {
9731 scsiq->q1.q_no = free_q_head;
9732 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9733 free_q_head)) == 1) {
9734 AscPutVarFreeQHead(iop_base, next_qp);
9735 asc_dvc->cur_total_qng++;
9736 asc_dvc->cur_dvc_qng[tid_no]++;
9737 }
9738 return (sta);
9739 }
9740 }
9741 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009742}
9743
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009744static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009745{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009746 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009747
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009748 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9749 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9750 n_sg_list_qs++;
9751 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009752}
9753
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009754static uint
9755AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009756{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009757 uint cur_used_qs;
9758 uint cur_free_qs;
9759 ASC_SCSI_BIT_ID_TYPE target_id;
9760 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009762 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9763 tid_no = ASC_TIX_TO_TID(target_ix);
9764 if ((asc_dvc->unit_not_ready & target_id) ||
9765 (asc_dvc->queue_full_or_busy & target_id)) {
9766 return (0);
9767 }
9768 if (n_qs == 1) {
9769 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9770 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9771 } else {
9772 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9773 (uint) ASC_MIN_FREE_Q;
9774 }
9775 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9776 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9777 if (asc_dvc->cur_dvc_qng[tid_no] >=
9778 asc_dvc->max_dvc_qng[tid_no]) {
9779 return (0);
9780 }
9781 return (cur_free_qs);
9782 }
9783 if (n_qs > 1) {
9784 if ((n_qs > asc_dvc->last_q_shortage)
9785 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9786 asc_dvc->last_q_shortage = n_qs;
9787 }
9788 }
9789 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009790}
9791
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009792static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009793{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009794 ushort q_addr;
9795 uchar tid_no;
9796 uchar sdtr_data;
9797 uchar syn_period_ix;
9798 uchar syn_offset;
9799 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009801 iop_base = asc_dvc->iop_base;
9802 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9803 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9804 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9805 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9806 syn_period_ix =
9807 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9808 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9809 AscMsgOutSDTR(asc_dvc,
9810 asc_dvc->sdtr_period_tbl[syn_period_ix],
9811 syn_offset);
9812 scsiq->q1.cntl |= QC_MSG_OUT;
9813 }
9814 q_addr = ASC_QNO_TO_QADDR(q_no);
9815 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9816 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9817 }
9818 scsiq->q1.status = QS_FREE;
9819 AscMemWordCopyPtrToLram(iop_base,
9820 q_addr + ASC_SCSIQ_CDB_BEG,
9821 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009822
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009823 DvcPutScsiQ(iop_base,
9824 q_addr + ASC_SCSIQ_CPY_BEG,
9825 (uchar *)&scsiq->q1.cntl,
9826 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9827 AscWriteLramWord(iop_base,
9828 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9829 (ushort)(((ushort)scsiq->q1.
9830 q_no << 8) | (ushort)QS_READY));
9831 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009832}
9833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009834static int
9835AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009836{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009837 int sta;
9838 int i;
9839 ASC_SG_HEAD *sg_head;
9840 ASC_SG_LIST_Q scsi_sg_q;
9841 ASC_DCNT saved_data_addr;
9842 ASC_DCNT saved_data_cnt;
9843 PortAddr iop_base;
9844 ushort sg_list_dwords;
9845 ushort sg_index;
9846 ushort sg_entry_cnt;
9847 ushort q_addr;
9848 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009850 iop_base = asc_dvc->iop_base;
9851 sg_head = scsiq->sg_head;
9852 saved_data_addr = scsiq->q1.data_addr;
9853 saved_data_cnt = scsiq->q1.data_cnt;
9854 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9855 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009856#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009857 /*
9858 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9859 * then not all SG elements will fit in the allocated queues.
9860 * The rest of the SG elements will be copied when the RISC
9861 * completes the SG elements that fit and halts.
9862 */
9863 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9864 /*
9865 * Set sg_entry_cnt to be the number of SG elements that
9866 * will fit in the allocated SG queues. It is minus 1, because
9867 * the first SG element is handled above. ASC_MAX_SG_LIST is
9868 * already inflated by 1 to account for this. For example it
9869 * may be 50 which is 1 + 7 queues * 7 SG elements.
9870 */
9871 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009872
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009873 /*
9874 * Keep track of remaining number of SG elements that will
9875 * need to be handled from a_isr.c.
9876 */
9877 scsiq->remain_sg_entry_cnt =
9878 sg_head->entry_cnt - ASC_MAX_SG_LIST;
9879 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009880#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009881 /*
9882 * Set sg_entry_cnt to be the number of SG elements that
9883 * will fit in the allocated SG queues. It is minus 1, because
9884 * the first SG element is handled above.
9885 */
9886 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009887#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009889#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009890 if (sg_entry_cnt != 0) {
9891 scsiq->q1.cntl |= QC_SG_HEAD;
9892 q_addr = ASC_QNO_TO_QADDR(q_no);
9893 sg_index = 1;
9894 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
9895 scsi_sg_q.sg_head_qp = q_no;
9896 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
9897 for (i = 0; i < sg_head->queue_cnt; i++) {
9898 scsi_sg_q.seq_no = i + 1;
9899 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
9900 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
9901 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
9902 if (i == 0) {
9903 scsi_sg_q.sg_list_cnt =
9904 ASC_SG_LIST_PER_Q;
9905 scsi_sg_q.sg_cur_list_cnt =
9906 ASC_SG_LIST_PER_Q;
9907 } else {
9908 scsi_sg_q.sg_list_cnt =
9909 ASC_SG_LIST_PER_Q - 1;
9910 scsi_sg_q.sg_cur_list_cnt =
9911 ASC_SG_LIST_PER_Q - 1;
9912 }
9913 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009914#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009915 /*
9916 * This is the last SG queue in the list of
9917 * allocated SG queues. If there are more
9918 * SG elements than will fit in the allocated
9919 * queues, then set the QCSG_SG_XFER_MORE flag.
9920 */
9921 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9922 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
9923 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009924#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009925 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009926#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009928#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009929 sg_list_dwords = sg_entry_cnt << 1;
9930 if (i == 0) {
9931 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
9932 scsi_sg_q.sg_cur_list_cnt =
9933 sg_entry_cnt;
9934 } else {
9935 scsi_sg_q.sg_list_cnt =
9936 sg_entry_cnt - 1;
9937 scsi_sg_q.sg_cur_list_cnt =
9938 sg_entry_cnt - 1;
9939 }
9940 sg_entry_cnt = 0;
9941 }
9942 next_qp = AscReadLramByte(iop_base,
9943 (ushort)(q_addr +
9944 ASC_SCSIQ_B_FWD));
9945 scsi_sg_q.q_no = next_qp;
9946 q_addr = ASC_QNO_TO_QADDR(next_qp);
9947 AscMemWordCopyPtrToLram(iop_base,
9948 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
9949 (uchar *)&scsi_sg_q,
9950 sizeof(ASC_SG_LIST_Q) >> 1);
9951 AscMemDWordCopyPtrToLram(iop_base,
9952 q_addr + ASC_SGQ_LIST_BEG,
9953 (uchar *)&sg_head->
9954 sg_list[sg_index],
9955 sg_list_dwords);
9956 sg_index += ASC_SG_LIST_PER_Q;
9957 scsiq->next_sg_index = sg_index;
9958 }
9959 } else {
9960 scsiq->q1.cntl &= ~QC_SG_HEAD;
9961 }
9962 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
9963 scsiq->q1.data_addr = saved_data_addr;
9964 scsiq->q1.data_cnt = saved_data_cnt;
9965 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009966}
9967
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009968static int
9969AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009970{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009971 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009972
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009973 if (AscHostReqRiscHalt(iop_base)) {
9974 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9975 AscStartChip(iop_base);
9976 return (sta);
9977 }
9978 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009979}
9980
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009981static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009982{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009983 ASC_SCSI_BIT_ID_TYPE org_id;
9984 int i;
9985 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009986
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009987 AscSetBank(iop_base, 1);
9988 org_id = AscReadChipDvcID(iop_base);
9989 for (i = 0; i <= ASC_MAX_TID; i++) {
9990 if (org_id == (0x01 << i))
9991 break;
9992 }
9993 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
9994 AscWriteChipDvcID(iop_base, id);
9995 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
9996 AscSetBank(iop_base, 0);
9997 AscSetChipSyn(iop_base, sdtr_data);
9998 if (AscGetChipSyn(iop_base) != sdtr_data) {
9999 sta = FALSE;
10000 }
10001 } else {
10002 sta = FALSE;
10003 }
10004 AscSetBank(iop_base, 1);
10005 AscWriteChipDvcID(iop_base, org_id);
10006 AscSetBank(iop_base, 0);
10007 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010008}
10009
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010010static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010011{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010012 uchar i;
10013 ushort s_addr;
10014 PortAddr iop_base;
10015 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010016
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010017 iop_base = asc_dvc->iop_base;
10018 warn_code = 0;
10019 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
10020 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
10021 64) >> 1)
10022 );
10023 i = ASC_MIN_ACTIVE_QNO;
10024 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
10025 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10026 (uchar)(i + 1));
10027 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10028 (uchar)(asc_dvc->max_total_qng));
10029 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10030 (uchar)i);
10031 i++;
10032 s_addr += ASC_QBLK_SIZE;
10033 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
10034 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10035 (uchar)(i + 1));
10036 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10037 (uchar)(i - 1));
10038 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10039 (uchar)i);
10040 }
10041 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
10042 (uchar)ASC_QLINK_END);
10043 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
10044 (uchar)(asc_dvc->max_total_qng - 1));
10045 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
10046 (uchar)asc_dvc->max_total_qng);
10047 i++;
10048 s_addr += ASC_QBLK_SIZE;
10049 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
10050 i++, s_addr += ASC_QBLK_SIZE) {
10051 AscWriteLramByte(iop_base,
10052 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
10053 AscWriteLramByte(iop_base,
10054 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
10055 AscWriteLramByte(iop_base,
10056 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
10057 }
10058 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010059}
10060
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010061static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010062{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010063 PortAddr iop_base;
10064 int i;
10065 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010066
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010067 iop_base = asc_dvc->iop_base;
10068 AscPutRiscVarFreeQHead(iop_base, 1);
10069 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
10070 AscPutVarFreeQHead(iop_base, 1);
10071 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
10072 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
10073 (uchar)((int)asc_dvc->max_total_qng + 1));
10074 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
10075 (uchar)((int)asc_dvc->max_total_qng + 2));
10076 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
10077 asc_dvc->max_total_qng);
10078 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
10079 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
10080 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
10081 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
10082 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
10083 AscPutQDoneInProgress(iop_base, 0);
10084 lram_addr = ASC_QADR_BEG;
10085 for (i = 0; i < 32; i++, lram_addr += 2) {
10086 AscWriteLramWord(iop_base, lram_addr, 0);
10087 }
10088 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010089}
10090
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010091static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010092{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010093 if (asc_dvc->err_code == 0) {
10094 asc_dvc->err_code = err_code;
10095 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
10096 err_code);
10097 }
10098 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010099}
10100
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010101static uchar
10102AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010103{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010104 EXT_MSG sdtr_buf;
10105 uchar sdtr_period_index;
10106 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010107
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010108 iop_base = asc_dvc->iop_base;
10109 sdtr_buf.msg_type = MS_EXTEND;
10110 sdtr_buf.msg_len = MS_SDTR_LEN;
10111 sdtr_buf.msg_req = MS_SDTR_CODE;
10112 sdtr_buf.xfer_period = sdtr_period;
10113 sdtr_offset &= ASC_SYN_MAX_OFFSET;
10114 sdtr_buf.req_ack_offset = sdtr_offset;
10115 if ((sdtr_period_index =
10116 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
10117 asc_dvc->max_sdtr_index) {
10118 AscMemWordCopyPtrToLram(iop_base,
10119 ASCV_MSGOUT_BEG,
10120 (uchar *)&sdtr_buf,
10121 sizeof(EXT_MSG) >> 1);
10122 return ((sdtr_period_index << 4) | sdtr_offset);
10123 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010124
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010125 sdtr_buf.req_ack_offset = 0;
10126 AscMemWordCopyPtrToLram(iop_base,
10127 ASCV_MSGOUT_BEG,
10128 (uchar *)&sdtr_buf,
10129 sizeof(EXT_MSG) >> 1);
10130 return (0);
10131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010132}
10133
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010134static uchar
10135AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010136{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010137 uchar byte;
10138 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010139
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010140 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
10141 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
10142 ) {
10143 return (0xFF);
10144 }
10145 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
10146 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010147}
10148
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010149static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010150{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010151 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
10152 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
10153 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010154}
10155
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010156static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010157{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010158 uchar *period_table;
10159 int max_index;
10160 int min_index;
10161 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010162
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010163 period_table = asc_dvc->sdtr_period_tbl;
10164 max_index = (int)asc_dvc->max_sdtr_index;
10165 min_index = (int)asc_dvc->host_init_sdtr_index;
10166 if ((syn_time <= period_table[max_index])) {
10167 for (i = min_index; i < (max_index - 1); i++) {
10168 if (syn_time <= period_table[i]) {
10169 return ((uchar)i);
10170 }
10171 }
10172 return ((uchar)max_index);
10173 } else {
10174 return ((uchar)(max_index + 1));
10175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010176}
10177
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010178static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010179{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010180 ushort q_addr;
10181 uchar next_qp;
10182 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010183
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010184 q_addr = ASC_QNO_TO_QADDR(free_q_head);
10185 q_status = (uchar)AscReadLramByte(iop_base,
10186 (ushort)(q_addr +
10187 ASC_SCSIQ_B_STATUS));
10188 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
10189 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
10190 return (next_qp);
10191 }
10192 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010193}
10194
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010195static uchar
10196AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010197{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010198 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010199
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010200 for (i = 0; i < n_free_q; i++) {
10201 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
10202 == ASC_QLINK_END) {
10203 return (ASC_QLINK_END);
10204 }
10205 }
10206 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010207}
10208
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010209static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010210{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010211 int count = 0;
10212 int sta = 0;
10213 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010214
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010215 if (AscIsChipHalted(iop_base))
10216 return (1);
10217 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
10218 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10219 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
10220 do {
10221 if (AscIsChipHalted(iop_base)) {
10222 sta = 1;
10223 break;
10224 }
10225 DvcSleepMilliSecond(100);
10226 } while (count++ < 20);
10227 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
10228 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010229}
10230
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010231static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010232{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010233 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010234
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010235 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
10236 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10237 ASC_STOP_REQ_RISC_STOP);
10238 do {
10239 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
10240 ASC_STOP_ACK_RISC_STOP) {
10241 return (1);
10242 }
10243 DvcSleepMilliSecond(100);
10244 } while (count++ < 20);
10245 }
10246 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010247}
10248
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010249static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010250{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010251 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010252}
10253
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010254static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010255{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010256 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010257}
10258
10259#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010260static ASC_DCNT __init AscGetEisaProductID(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010261{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010262 PortAddr eisa_iop;
10263 ushort product_id_high, product_id_low;
10264 ASC_DCNT product_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010265
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010266 eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
10267 product_id_low = inpw(eisa_iop);
10268 product_id_high = inpw(eisa_iop + 2);
10269 product_id = ((ASC_DCNT) product_id_high << 16) |
10270 (ASC_DCNT) product_id_low;
10271 return (product_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010272}
10273
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010274static PortAddr __init AscSearchIOPortAddrEISA(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010275{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010276 ASC_DCNT eisa_product_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010277
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010278 if (iop_base == 0) {
10279 iop_base = ASC_EISA_MIN_IOP_ADDR;
10280 } else {
10281 if (iop_base == ASC_EISA_MAX_IOP_ADDR)
10282 return (0);
10283 if ((iop_base & 0x0050) == 0x0050) {
10284 iop_base += ASC_EISA_BIG_IOP_GAP;
10285 } else {
10286 iop_base += ASC_EISA_SMALL_IOP_GAP;
10287 }
10288 }
10289 while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
10290 eisa_product_id = AscGetEisaProductID(iop_base);
10291 if ((eisa_product_id == ASC_EISA_ID_740) ||
10292 (eisa_product_id == ASC_EISA_ID_750)) {
10293 if (AscFindSignature(iop_base)) {
10294 inpw(iop_base + 4);
10295 return (iop_base);
10296 }
10297 }
10298 if (iop_base == ASC_EISA_MAX_IOP_ADDR)
10299 return (0);
10300 if ((iop_base & 0x0050) == 0x0050) {
10301 iop_base += ASC_EISA_BIG_IOP_GAP;
10302 } else {
10303 iop_base += ASC_EISA_SMALL_IOP_GAP;
10304 }
10305 }
10306 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010307}
10308#endif /* CONFIG_ISA */
10309
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010310static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010311{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010312 AscSetChipControl(iop_base, 0);
10313 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10314 return (0);
10315 }
10316 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010317}
10318
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010319static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010320{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010321 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010322
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010323 cc_val =
10324 AscGetChipControl(iop_base) &
10325 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
10326 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
10327 AscSetChipIH(iop_base, INS_HALT);
10328 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10329 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
10330 return (0);
10331 }
10332 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010333}
10334
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010335static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010336{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010337 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10338 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
10339 return (1);
10340 }
10341 }
10342 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010343}
10344
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010345static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010346{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010347 AscSetBank(iop_base, 1);
10348 AscWriteChipIH(iop_base, ins_code);
10349 AscSetBank(iop_base, 0);
10350 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010351}
10352
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010353static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010354{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010355 uchar host_flag;
10356 uchar risc_flag;
10357 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010358
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010359 loop = 0;
10360 do {
10361 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10362 if (loop++ > 0x7FFF) {
10363 break;
10364 }
10365 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10366 host_flag =
10367 AscReadLramByte(iop_base,
10368 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10369 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10370 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10371 AscSetChipStatus(iop_base, CIW_INT_ACK);
10372 loop = 0;
10373 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10374 AscSetChipStatus(iop_base, CIW_INT_ACK);
10375 if (loop++ > 3) {
10376 break;
10377 }
10378 }
10379 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10380 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010381}
10382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010383static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010384{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010385 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010386
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010387 cfg = AscGetChipCfgLsw(iop_base);
10388 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10389 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010390}
10391
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010392static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010393{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010394 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010395
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010396 cfg = AscGetChipCfgLsw(iop_base);
10397 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10398 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010399}
10400
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010401static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010402{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010403 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010404
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010405 val = AscGetChipControl(iop_base) &
10406 (~
10407 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10408 CC_CHIP_RESET));
10409 if (bank == 1) {
10410 val |= CC_BANK_ONE;
10411 } else if (bank == 2) {
10412 val |= CC_DIAG | CC_BANK_ONE;
10413 } else {
10414 val &= ~CC_BANK_ONE;
10415 }
10416 AscSetChipControl(iop_base, val);
10417 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010418}
10419
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010420static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010421{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010422 PortAddr iop_base;
10423 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010424
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010425 iop_base = asc_dvc->iop_base;
10426 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10427 && (i-- > 0)) {
10428 DvcSleepMilliSecond(100);
10429 }
10430 AscStopChip(iop_base);
10431 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10432 DvcDelayNanoSecond(asc_dvc, 60000);
10433 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10434 AscSetChipIH(iop_base, INS_HALT);
10435 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10436 AscSetChipControl(iop_base, CC_HALT);
10437 DvcSleepMilliSecond(200);
10438 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10439 AscSetChipStatus(iop_base, 0);
10440 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010441}
10442
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010443static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010444{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010445 if (bus_type & ASC_IS_ISA)
10446 return (ASC_MAX_ISA_DMA_COUNT);
10447 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10448 return (ASC_MAX_VL_DMA_COUNT);
10449 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010450}
10451
10452#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010453static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010454{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010455 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010456
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010457 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10458 if (channel == 0x03)
10459 return (0);
10460 else if (channel == 0x00)
10461 return (7);
10462 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010463}
10464
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010465static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010466{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010467 ushort cfg_lsw;
10468 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010469
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010470 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10471 if (dma_channel == 7)
10472 value = 0x00;
10473 else
10474 value = dma_channel - 4;
10475 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10476 cfg_lsw |= value;
10477 AscSetChipCfgLsw(iop_base, cfg_lsw);
10478 return (AscGetIsaDmaChannel(iop_base));
10479 }
10480 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010481}
10482
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010483static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010484{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010485 speed_value &= 0x07;
10486 AscSetBank(iop_base, 1);
10487 AscWriteChipDmaSpeed(iop_base, speed_value);
10488 AscSetBank(iop_base, 0);
10489 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010490}
10491
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010492static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010493{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010494 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010495
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010496 AscSetBank(iop_base, 1);
10497 speed_value = AscReadChipDmaSpeed(iop_base);
10498 speed_value &= 0x07;
10499 AscSetBank(iop_base, 0);
10500 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010501}
10502#endif /* CONFIG_ISA */
10503
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010504static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010505AscReadPCIConfigWord(ASC_DVC_VAR *asc_dvc, ushort pci_config_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010506{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010507 uchar lsb, msb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010508
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010509 lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
10510 msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
10511 return ((ushort)((msb << 8) | lsb));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010512}
10513
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010514static ushort __devinit AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010515{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010516 ushort warn_code;
10517 PortAddr iop_base;
10518 ushort PCIDeviceID;
10519 ushort PCIVendorID;
10520 uchar PCIRevisionID;
10521 uchar prevCmdRegBits;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010522
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010523 warn_code = 0;
10524 iop_base = asc_dvc->iop_base;
10525 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
10526 if (asc_dvc->err_code != 0) {
10527 return (UW_ERR);
10528 }
10529 if (asc_dvc->bus_type == ASC_IS_PCI) {
10530 PCIVendorID = AscReadPCIConfigWord(asc_dvc,
10531 AscPCIConfigVendorIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010532
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010533 PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
10534 AscPCIConfigDeviceIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010535
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010536 PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
10537 AscPCIConfigRevisionIDRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010538
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010539 if (PCIVendorID != PCI_VENDOR_ID_ASP) {
10540 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10541 }
10542 prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
10543 AscPCIConfigCommandRegister);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010544
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010545 if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
10546 AscPCICmdRegBits_IOMemBusMaster) {
10547 DvcWritePCIConfigByte(asc_dvc,
10548 AscPCIConfigCommandRegister,
10549 (prevCmdRegBits |
10550 AscPCICmdRegBits_IOMemBusMaster));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010551
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010552 if ((DvcReadPCIConfigByte(asc_dvc,
10553 AscPCIConfigCommandRegister)
10554 & AscPCICmdRegBits_IOMemBusMaster)
10555 != AscPCICmdRegBits_IOMemBusMaster) {
10556 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10557 }
10558 }
10559 if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
10560 (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
10561 DvcWritePCIConfigByte(asc_dvc,
10562 AscPCIConfigLatencyTimer, 0x00);
10563 if (DvcReadPCIConfigByte
10564 (asc_dvc, AscPCIConfigLatencyTimer)
10565 != 0x00) {
10566 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
10567 }
10568 } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
10569 if (DvcReadPCIConfigByte(asc_dvc,
10570 AscPCIConfigLatencyTimer) <
10571 0x20) {
10572 DvcWritePCIConfigByte(asc_dvc,
10573 AscPCIConfigLatencyTimer,
10574 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010575
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010576 if (DvcReadPCIConfigByte(asc_dvc,
10577 AscPCIConfigLatencyTimer)
10578 < 0x20) {
10579 warn_code |=
10580 ASC_WARN_SET_PCI_CONFIG_SPACE;
10581 }
10582 }
10583 }
10584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010585
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010586 if (AscFindSignature(iop_base)) {
10587 warn_code |= AscInitAscDvcVar(asc_dvc);
10588 warn_code |= AscInitFromEEP(asc_dvc);
10589 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
10590 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
10591 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
10592 }
10593 } else {
10594 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10595 }
10596 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010597}
10598
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010599static ushort __devinit AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010600{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010601 ushort warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010602
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010603 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10604 if (asc_dvc->err_code != 0)
10605 return (UW_ERR);
10606 if (AscFindSignature(asc_dvc->iop_base)) {
10607 warn_code |= AscInitFromAscDvcVar(asc_dvc);
10608 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10609 } else {
10610 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10611 }
10612 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010613}
10614
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010615static ushort __devinit AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010616{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010617 PortAddr iop_base;
10618 ushort cfg_msw;
10619 ushort warn_code;
10620 ushort pci_device_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010621
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010622 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010623#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010624 if (asc_dvc->cfg->dev)
10625 pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010626#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010627 warn_code = 0;
10628 cfg_msw = AscGetChipCfgMsw(iop_base);
10629 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10630 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10631 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10632 AscSetChipCfgMsw(iop_base, cfg_msw);
10633 }
10634 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10635 asc_dvc->cfg->cmd_qng_enabled) {
10636 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10637 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10638 }
10639 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10640 warn_code |= ASC_WARN_AUTO_CONFIG;
10641 }
10642 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10643 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10644 != asc_dvc->irq_no) {
10645 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10646 }
10647 }
10648 if (asc_dvc->bus_type & ASC_IS_PCI) {
10649 cfg_msw &= 0xFFC0;
10650 AscSetChipCfgMsw(iop_base, cfg_msw);
10651 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10652 } else {
10653 if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
10654 (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
10655 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10656 asc_dvc->bug_fix_cntl |=
10657 ASC_BUG_FIX_ASYN_USE_SYN;
10658 }
10659 }
10660 } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
10661 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10662 == ASC_CHIP_VER_ASYN_BUG) {
10663 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10664 }
10665 }
10666 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10667 asc_dvc->cfg->chip_scsi_id) {
10668 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010670#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010671 if (asc_dvc->bus_type & ASC_IS_ISA) {
10672 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10673 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010675#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010676 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010677}
10678
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010679static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010680{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010681 ushort warn_code;
10682 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010683
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010684 iop_base = asc_dvc->iop_base;
10685 warn_code = 0;
10686 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10687 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10688 AscResetChipAndScsiBus(asc_dvc);
10689 DvcSleepMilliSecond((ASC_DCNT)
10690 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10691 }
10692 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10693 if (asc_dvc->err_code != 0)
10694 return (UW_ERR);
10695 if (!AscFindSignature(asc_dvc->iop_base)) {
10696 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10697 return (warn_code);
10698 }
10699 AscDisableInterrupt(iop_base);
10700 warn_code |= AscInitLram(asc_dvc);
10701 if (asc_dvc->err_code != 0)
10702 return (UW_ERR);
10703 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10704 (ulong)_asc_mcode_chksum);
10705 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10706 _asc_mcode_size) != _asc_mcode_chksum) {
10707 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10708 return (warn_code);
10709 }
10710 warn_code |= AscInitMicroCodeVar(asc_dvc);
10711 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10712 AscEnableInterrupt(iop_base);
10713 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010714}
10715
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010716static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010717{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010718 int i;
10719 PortAddr iop_base;
10720 ushort warn_code;
10721 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010722
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010723 iop_base = asc_dvc->iop_base;
10724 warn_code = 0;
10725 asc_dvc->err_code = 0;
10726 if ((asc_dvc->bus_type &
10727 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10728 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10729 }
10730 AscSetChipControl(iop_base, CC_HALT);
10731 AscSetChipStatus(iop_base, 0);
10732 asc_dvc->bug_fix_cntl = 0;
10733 asc_dvc->pci_fix_asyn_xfer = 0;
10734 asc_dvc->pci_fix_asyn_xfer_always = 0;
10735 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10736 asc_dvc->sdtr_done = 0;
10737 asc_dvc->cur_total_qng = 0;
10738 asc_dvc->is_in_int = 0;
10739 asc_dvc->in_critical_cnt = 0;
10740 asc_dvc->last_q_shortage = 0;
10741 asc_dvc->use_tagged_qng = 0;
10742 asc_dvc->no_scam = 0;
10743 asc_dvc->unit_not_ready = 0;
10744 asc_dvc->queue_full_or_busy = 0;
10745 asc_dvc->redo_scam = 0;
10746 asc_dvc->res2 = 0;
10747 asc_dvc->host_init_sdtr_index = 0;
10748 asc_dvc->cfg->can_tagged_qng = 0;
10749 asc_dvc->cfg->cmd_qng_enabled = 0;
10750 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10751 asc_dvc->init_sdtr = 0;
10752 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10753 asc_dvc->scsi_reset_wait = 3;
10754 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10755 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10756 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10757 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10758 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10759 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10760 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10761 ASC_LIB_VERSION_MINOR;
10762 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10763 asc_dvc->cfg->chip_version = chip_version;
10764 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10765 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10766 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10767 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10768 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10769 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10770 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10771 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10772 asc_dvc->max_sdtr_index = 7;
10773 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10774 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10775 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10776 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10777 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10778 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10779 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10780 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10781 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10782 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10783 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10784 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10785 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10786 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10787 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10788 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10789 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10790 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10791 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10792 asc_dvc->max_sdtr_index = 15;
10793 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10794 AscSetExtraControl(iop_base,
10795 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10796 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10797 AscSetExtraControl(iop_base,
10798 (SEC_ACTIVE_NEGATE |
10799 SEC_ENABLE_FILTER));
10800 }
10801 }
10802 if (asc_dvc->bus_type == ASC_IS_PCI) {
10803 AscSetExtraControl(iop_base,
10804 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010807 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
10808 if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
10809 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10810 asc_dvc->bus_type = ASC_IS_ISAPNP;
10811 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010812#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010813 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
10814 asc_dvc->cfg->isa_dma_channel =
10815 (uchar)AscGetIsaDmaChannel(iop_base);
10816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010817#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010818 for (i = 0; i <= ASC_MAX_TID; i++) {
10819 asc_dvc->cur_dvc_qng[i] = 0;
10820 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10821 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10822 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10823 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10824 }
10825 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010826}
10827
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010828static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010829{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010830 ASCEEP_CONFIG eep_config_buf;
10831 ASCEEP_CONFIG *eep_config;
10832 PortAddr iop_base;
10833 ushort chksum;
10834 ushort warn_code;
10835 ushort cfg_msw, cfg_lsw;
10836 int i;
10837 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010838
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010839 iop_base = asc_dvc->iop_base;
10840 warn_code = 0;
10841 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10842 AscStopQueueExe(iop_base);
10843 if ((AscStopChip(iop_base) == FALSE) ||
10844 (AscGetChipScsiCtrl(iop_base) != 0)) {
10845 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10846 AscResetChipAndScsiBus(asc_dvc);
10847 DvcSleepMilliSecond((ASC_DCNT)
10848 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10849 }
10850 if (AscIsChipHalted(iop_base) == FALSE) {
10851 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10852 return (warn_code);
10853 }
10854 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10855 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10856 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10857 return (warn_code);
10858 }
10859 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10860 cfg_msw = AscGetChipCfgMsw(iop_base);
10861 cfg_lsw = AscGetChipCfgLsw(iop_base);
10862 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10863 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10864 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10865 AscSetChipCfgMsw(iop_base, cfg_msw);
10866 }
10867 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
10868 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
10869 if (chksum == 0) {
10870 chksum = 0xaa55;
10871 }
10872 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10873 warn_code |= ASC_WARN_AUTO_CONFIG;
10874 if (asc_dvc->cfg->chip_version == 3) {
10875 if (eep_config->cfg_lsw != cfg_lsw) {
10876 warn_code |= ASC_WARN_EEPROM_RECOVER;
10877 eep_config->cfg_lsw =
10878 AscGetChipCfgLsw(iop_base);
10879 }
10880 if (eep_config->cfg_msw != cfg_msw) {
10881 warn_code |= ASC_WARN_EEPROM_RECOVER;
10882 eep_config->cfg_msw =
10883 AscGetChipCfgMsw(iop_base);
10884 }
10885 }
10886 }
10887 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
10888 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
10889 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
10890 eep_config->chksum);
10891 if (chksum != eep_config->chksum) {
10892 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
10893 ASC_CHIP_VER_PCI_ULTRA_3050) {
10894 ASC_DBG(1,
10895 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
10896 eep_config->init_sdtr = 0xFF;
10897 eep_config->disc_enable = 0xFF;
10898 eep_config->start_motor = 0xFF;
10899 eep_config->use_cmd_qng = 0;
10900 eep_config->max_total_qng = 0xF0;
10901 eep_config->max_tag_qng = 0x20;
10902 eep_config->cntl = 0xBFFF;
10903 ASC_EEP_SET_CHIP_ID(eep_config, 7);
10904 eep_config->no_scam = 0;
10905 eep_config->adapter_info[0] = 0;
10906 eep_config->adapter_info[1] = 0;
10907 eep_config->adapter_info[2] = 0;
10908 eep_config->adapter_info[3] = 0;
10909 eep_config->adapter_info[4] = 0;
10910 /* Indicate EEPROM-less board. */
10911 eep_config->adapter_info[5] = 0xBB;
10912 } else {
10913 ASC_PRINT
10914 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
10915 write_eep = 1;
10916 warn_code |= ASC_WARN_EEPROM_CHKSUM;
10917 }
10918 }
10919 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
10920 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
10921 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
10922 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
10923 asc_dvc->start_motor = eep_config->start_motor;
10924 asc_dvc->dvc_cntl = eep_config->cntl;
10925 asc_dvc->no_scam = eep_config->no_scam;
10926 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
10927 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
10928 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
10929 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
10930 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
10931 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
10932 if (!AscTestExternalLram(asc_dvc)) {
10933 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
10934 ASC_IS_PCI_ULTRA)) {
10935 eep_config->max_total_qng =
10936 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
10937 eep_config->max_tag_qng =
10938 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
10939 } else {
10940 eep_config->cfg_msw |= 0x0800;
10941 cfg_msw |= 0x0800;
10942 AscSetChipCfgMsw(iop_base, cfg_msw);
10943 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
10944 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
10945 }
10946 } else {
10947 }
10948 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
10949 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
10950 }
10951 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
10952 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
10953 }
10954 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
10955 eep_config->max_tag_qng = eep_config->max_total_qng;
10956 }
10957 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
10958 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
10959 }
10960 asc_dvc->max_total_qng = eep_config->max_total_qng;
10961 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
10962 eep_config->use_cmd_qng) {
10963 eep_config->disc_enable = eep_config->use_cmd_qng;
10964 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10965 }
10966 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
10967 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
10968 }
10969 ASC_EEP_SET_CHIP_ID(eep_config,
10970 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
10971 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
10972 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
10973 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
10974 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
10975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010976
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010977 for (i = 0; i <= ASC_MAX_TID; i++) {
10978 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
10979 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
10980 asc_dvc->cfg->sdtr_period_offset[i] =
10981 (uchar)(ASC_DEF_SDTR_OFFSET |
10982 (asc_dvc->host_init_sdtr_index << 4));
10983 }
10984 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
10985 if (write_eep) {
10986 if ((i =
10987 AscSetEEPConfig(iop_base, eep_config,
10988 asc_dvc->bus_type)) != 0) {
10989 ASC_PRINT1
10990 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
10991 i);
10992 } else {
10993 ASC_PRINT
10994 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
10995 }
10996 }
10997 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010998}
10999
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011000static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011001{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011002 int i;
11003 ushort warn_code;
11004 PortAddr iop_base;
11005 ASC_PADDR phy_addr;
11006 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011007
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011008 iop_base = asc_dvc->iop_base;
11009 warn_code = 0;
11010 for (i = 0; i <= ASC_MAX_TID; i++) {
11011 AscPutMCodeInitSDTRAtID(iop_base, i,
11012 asc_dvc->cfg->sdtr_period_offset[i]
11013 );
11014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011015
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011016 AscInitQLinkVar(asc_dvc);
11017 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
11018 asc_dvc->cfg->disc_enable);
11019 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
11020 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070011021
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011022 /* Align overrun buffer on an 8 byte boundary. */
11023 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
11024 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
11025 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
11026 (uchar *)&phy_addr, 1);
11027 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
11028 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
11029 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011031 asc_dvc->cfg->mcode_date =
11032 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
11033 asc_dvc->cfg->mcode_version =
11034 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011035
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011036 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
11037 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
11038 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
11039 return (warn_code);
11040 }
11041 if (AscStartChip(iop_base) != 1) {
11042 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
11043 return (warn_code);
11044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011045
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011046 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011047}
11048
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011049static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011050{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011051 PortAddr iop_base;
11052 ushort q_addr;
11053 ushort saved_word;
11054 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011055
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011056 iop_base = asc_dvc->iop_base;
11057 sta = 0;
11058 q_addr = ASC_QNO_TO_QADDR(241);
11059 saved_word = AscReadLramWord(iop_base, q_addr);
11060 AscSetChipLramAddr(iop_base, q_addr);
11061 AscSetChipLramData(iop_base, 0x55AA);
11062 DvcSleepMilliSecond(10);
11063 AscSetChipLramAddr(iop_base, q_addr);
11064 if (AscGetChipLramData(iop_base) == 0x55AA) {
11065 sta = 1;
11066 AscWriteLramWord(iop_base, q_addr, saved_word);
11067 }
11068 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011069}
11070
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011071static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011072{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011073 uchar read_back;
11074 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011075
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011076 retry = 0;
11077 while (TRUE) {
11078 AscSetChipEEPCmd(iop_base, cmd_reg);
11079 DvcSleepMilliSecond(1);
11080 read_back = AscGetChipEEPCmd(iop_base);
11081 if (read_back == cmd_reg) {
11082 return (1);
11083 }
11084 if (retry++ > ASC_EEP_MAX_RETRY) {
11085 return (0);
11086 }
11087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011088}
11089
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011090static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011091{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011092 ushort read_back;
11093 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011094
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011095 retry = 0;
11096 while (TRUE) {
11097 AscSetChipEEPData(iop_base, data_reg);
11098 DvcSleepMilliSecond(1);
11099 read_back = AscGetChipEEPData(iop_base);
11100 if (read_back == data_reg) {
11101 return (1);
11102 }
11103 if (retry++ > ASC_EEP_MAX_RETRY) {
11104 return (0);
11105 }
11106 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011107}
11108
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011109static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011110{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011111 DvcSleepMilliSecond(1);
11112 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011113}
11114
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011115static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011116{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011117 DvcSleepMilliSecond(20);
11118 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011119}
11120
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011121static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011122{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011123 ushort read_wval;
11124 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011125
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011126 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
11127 AscWaitEEPRead();
11128 cmd_reg = addr | ASC_EEP_CMD_READ;
11129 AscWriteEEPCmdReg(iop_base, cmd_reg);
11130 AscWaitEEPRead();
11131 read_wval = AscGetChipEEPData(iop_base);
11132 AscWaitEEPRead();
11133 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011134}
11135
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011136static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011137AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011138{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011139 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011140
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011141 read_wval = AscReadEEPWord(iop_base, addr);
11142 if (read_wval != word_val) {
11143 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
11144 AscWaitEEPRead();
11145 AscWriteEEPDataReg(iop_base, word_val);
11146 AscWaitEEPRead();
11147 AscWriteEEPCmdReg(iop_base,
11148 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
11149 AscWaitEEPWrite();
11150 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
11151 AscWaitEEPRead();
11152 return (AscReadEEPWord(iop_base, addr));
11153 }
11154 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011155}
11156
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011157static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011158AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011159{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011160 ushort wval;
11161 ushort sum;
11162 ushort *wbuf;
11163 int cfg_beg;
11164 int cfg_end;
11165 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
11166 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011167
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011168 wbuf = (ushort *)cfg_buf;
11169 sum = 0;
11170 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
11171 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11172 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
11173 sum += *wbuf;
11174 }
11175 if (bus_type & ASC_IS_VL) {
11176 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11177 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11178 } else {
11179 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11180 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11181 }
11182 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11183 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
11184 if (s_addr <= uchar_end_in_config) {
11185 /*
11186 * Swap all char fields - must unswap bytes already swapped
11187 * by AscReadEEPWord().
11188 */
11189 *wbuf = le16_to_cpu(wval);
11190 } else {
11191 /* Don't swap word field at the end - cntl field. */
11192 *wbuf = wval;
11193 }
11194 sum += wval; /* Checksum treats all EEPROM data as words. */
11195 }
11196 /*
11197 * Read the checksum word which will be compared against 'sum'
11198 * by the caller. Word field already swapped.
11199 */
11200 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
11201 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011202}
11203
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011204static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011205AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011206{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011207 int n_error;
11208 ushort *wbuf;
11209 ushort word;
11210 ushort sum;
11211 int s_addr;
11212 int cfg_beg;
11213 int cfg_end;
11214 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011215
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011216 wbuf = (ushort *)cfg_buf;
11217 n_error = 0;
11218 sum = 0;
11219 /* Write two config words; AscWriteEEPWord() will swap bytes. */
11220 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11221 sum += *wbuf;
11222 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
11223 n_error++;
11224 }
11225 }
11226 if (bus_type & ASC_IS_VL) {
11227 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11228 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11229 } else {
11230 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11231 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11232 }
11233 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11234 if (s_addr <= uchar_end_in_config) {
11235 /*
11236 * This is a char field. Swap char fields before they are
11237 * swapped again by AscWriteEEPWord().
11238 */
11239 word = cpu_to_le16(*wbuf);
11240 if (word !=
11241 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
11242 n_error++;
11243 }
11244 } else {
11245 /* Don't swap word field at the end - cntl field. */
11246 if (*wbuf !=
11247 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
11248 n_error++;
11249 }
11250 }
11251 sum += *wbuf; /* Checksum calculated from word values. */
11252 }
11253 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
11254 *wbuf = sum;
11255 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
11256 n_error++;
11257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011258
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011259 /* Read EEPROM back again. */
11260 wbuf = (ushort *)cfg_buf;
11261 /*
11262 * Read two config words; Byte-swapping done by AscReadEEPWord().
11263 */
11264 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
11265 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
11266 n_error++;
11267 }
11268 }
11269 if (bus_type & ASC_IS_VL) {
11270 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
11271 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
11272 } else {
11273 cfg_beg = ASC_EEP_DVC_CFG_BEG;
11274 cfg_end = ASC_EEP_MAX_DVC_ADDR;
11275 }
11276 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
11277 if (s_addr <= uchar_end_in_config) {
11278 /*
11279 * Swap all char fields. Must unswap bytes already swapped
11280 * by AscReadEEPWord().
11281 */
11282 word =
11283 le16_to_cpu(AscReadEEPWord
11284 (iop_base, (uchar)s_addr));
11285 } else {
11286 /* Don't swap word field at the end - cntl field. */
11287 word = AscReadEEPWord(iop_base, (uchar)s_addr);
11288 }
11289 if (*wbuf != word) {
11290 n_error++;
11291 }
11292 }
11293 /* Read checksum; Byte swapping not needed. */
11294 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
11295 n_error++;
11296 }
11297 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011298}
11299
Matthew Wilcox78e77d82007-07-29 21:46:15 -060011300static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011301AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011302{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011303 int retry;
11304 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011306 retry = 0;
11307 while (TRUE) {
11308 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
11309 bus_type)) == 0) {
11310 break;
11311 }
11312 if (++retry > ASC_EEP_MAX_RETRY) {
11313 break;
11314 }
11315 }
11316 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011317}
11318
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011319static void
11320AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011321{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011322 uchar dvc_type;
11323 ASC_SCSI_BIT_ID_TYPE tid_bits;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011324
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011325 dvc_type = ASC_INQ_DVC_TYPE(inq);
11326 tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011327
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011328 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
11329 if (!(asc_dvc->init_sdtr & tid_bits)) {
11330 if ((dvc_type == TYPE_ROM) &&
11331 (AscCompareString((uchar *)inq->vendor_id,
11332 (uchar *)"HP ", 3) == 0)) {
11333 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
11334 }
11335 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
11336 if ((dvc_type == TYPE_PROCESSOR) ||
11337 (dvc_type == TYPE_SCANNER) ||
11338 (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) {
11339 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
11340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011341
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011342 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
11343 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
11344 tid_no,
11345 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
11346 }
11347 }
11348 }
11349 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011350}
11351
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011352static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011353{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011354 if ((inq->add_len >= 32) &&
11355 (AscCompareString((uchar *)inq->vendor_id,
11356 (uchar *)"QUANTUM XP34301", 15) == 0) &&
11357 (AscCompareString((uchar *)inq->product_rev_level,
11358 (uchar *)"1071", 4) == 0)) {
11359 return 0;
11360 }
11361 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011362}
11363
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011364static void
11365AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011366{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011367 ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
11368 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011369
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011370 orig_init_sdtr = asc_dvc->init_sdtr;
11371 orig_use_tagged_qng = asc_dvc->use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011372
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011373 asc_dvc->init_sdtr &= ~tid_bit;
11374 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
11375 asc_dvc->use_tagged_qng &= ~tid_bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011376
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011377 if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
11378 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
11379 asc_dvc->init_sdtr |= tid_bit;
11380 }
11381 if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
11382 ASC_INQ_CMD_QUEUE(inq)) {
11383 if (AscTagQueuingSafe(inq)) {
11384 asc_dvc->use_tagged_qng |= tid_bit;
11385 asc_dvc->cfg->can_tagged_qng |= tid_bit;
11386 }
11387 }
11388 }
11389 if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
11390 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
11391 asc_dvc->cfg->disc_enable);
11392 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
11393 asc_dvc->use_tagged_qng);
11394 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
11395 asc_dvc->cfg->can_tagged_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011396
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011397 asc_dvc->max_dvc_qng[tid_no] =
11398 asc_dvc->cfg->max_tag_qng[tid_no];
11399 AscWriteLramByte(asc_dvc->iop_base,
11400 (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no),
11401 asc_dvc->max_dvc_qng[tid_no]);
11402 }
11403 if (orig_init_sdtr != asc_dvc->init_sdtr) {
11404 AscAsyncFix(asc_dvc, tid_no, inq);
11405 }
11406 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011407}
11408
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011409static int AscCompareString(uchar *str1, uchar *str2, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011410{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011411 int i;
11412 int diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011413
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011414 for (i = 0; i < len; i++) {
11415 diff = (int)(str1[i] - str2[i]);
11416 if (diff != 0)
11417 return (diff);
11418 }
11419 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011420}
11421
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011422static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011423{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011424 uchar byte_data;
11425 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011426
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011427 if (isodd_word(addr)) {
11428 AscSetChipLramAddr(iop_base, addr - 1);
11429 word_data = AscGetChipLramData(iop_base);
11430 byte_data = (uchar)((word_data >> 8) & 0xFF);
11431 } else {
11432 AscSetChipLramAddr(iop_base, addr);
11433 word_data = AscGetChipLramData(iop_base);
11434 byte_data = (uchar)(word_data & 0xFF);
11435 }
11436 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011437}
Linus Torvalds1da177e2005-04-16 15:20:36 -070011438
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011439static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
11440{
11441 ushort word_data;
11442
11443 AscSetChipLramAddr(iop_base, addr);
11444 word_data = AscGetChipLramData(iop_base);
11445 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011446}
11447
11448#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011449static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011450{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011451 ushort val_low, val_high;
11452 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011453
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011454 AscSetChipLramAddr(iop_base, addr);
11455 val_low = AscGetChipLramData(iop_base);
11456 val_high = AscGetChipLramData(iop_base);
11457 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
11458 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011459}
11460#endif /* CC_VERY_LONG_SG_LIST */
11461
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011462static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011463{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011464 AscSetChipLramAddr(iop_base, addr);
11465 AscSetChipLramData(iop_base, word_val);
11466 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011467}
11468
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011469static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011470{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011471 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011473 if (isodd_word(addr)) {
11474 addr--;
11475 word_data = AscReadLramWord(iop_base, addr);
11476 word_data &= 0x00FF;
11477 word_data |= (((ushort)byte_val << 8) & 0xFF00);
11478 } else {
11479 word_data = AscReadLramWord(iop_base, addr);
11480 word_data &= 0xFF00;
11481 word_data |= ((ushort)byte_val & 0x00FF);
11482 }
11483 AscWriteLramWord(iop_base, addr, word_data);
11484 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011485}
11486
11487/*
11488 * Copy 2 bytes to LRAM.
11489 *
11490 * The source data is assumed to be in little-endian order in memory
11491 * and is maintained in little-endian order when written to LRAM.
11492 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011493static void
11494AscMemWordCopyPtrToLram(PortAddr iop_base,
11495 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011496{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011497 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011498
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011499 AscSetChipLramAddr(iop_base, s_addr);
11500 for (i = 0; i < 2 * words; i += 2) {
11501 /*
11502 * On a little-endian system the second argument below
11503 * produces a little-endian ushort which is written to
11504 * LRAM in little-endian order. On a big-endian system
11505 * the second argument produces a big-endian ushort which
11506 * is "transparently" byte-swapped by outpw() and written
11507 * in little-endian order to LRAM.
11508 */
11509 outpw(iop_base + IOP_RAM_DATA,
11510 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
11511 }
11512 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011513}
11514
11515/*
11516 * Copy 4 bytes to LRAM.
11517 *
11518 * The source data is assumed to be in little-endian order in memory
11519 * and is maintained in little-endian order when writen to LRAM.
11520 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011521static void
11522AscMemDWordCopyPtrToLram(PortAddr iop_base,
11523 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011524{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011525 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011526
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011527 AscSetChipLramAddr(iop_base, s_addr);
11528 for (i = 0; i < 4 * dwords; i += 4) {
11529 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11530 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11531 }
11532 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011533}
11534
11535/*
11536 * Copy 2 bytes from LRAM.
11537 *
11538 * The source data is assumed to be in little-endian order in LRAM
11539 * and is maintained in little-endian order when written to memory.
11540 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011541static void
11542AscMemWordCopyPtrFromLram(PortAddr iop_base,
11543 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011544{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011545 int i;
11546 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011547
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011548 AscSetChipLramAddr(iop_base, s_addr);
11549 for (i = 0; i < 2 * words; i += 2) {
11550 word = inpw(iop_base + IOP_RAM_DATA);
11551 d_buffer[i] = word & 0xff;
11552 d_buffer[i + 1] = (word >> 8) & 0xff;
11553 }
11554 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011555}
11556
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011557static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011558{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011559 ASC_DCNT sum;
11560 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011561
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011562 sum = 0L;
11563 for (i = 0; i < words; i++, s_addr += 2) {
11564 sum += AscReadLramWord(iop_base, s_addr);
11565 }
11566 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011567}
11568
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011569static void
11570AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011571{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011572 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011573
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011574 AscSetChipLramAddr(iop_base, s_addr);
11575 for (i = 0; i < words; i++) {
11576 AscSetChipLramData(iop_base, set_wval);
11577 }
11578 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011579}
11580
Linus Torvalds1da177e2005-04-16 15:20:36 -070011581/*
11582 * --- Adv Library Functions
11583 */
11584
11585/* a_mcode.h */
11586
11587/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011588static unsigned char _adv_asc3550_buf[] = {
11589 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11590 0x01, 0x00, 0x48, 0xe4,
11591 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11592 0x28, 0x0e, 0x9e, 0xe7,
11593 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11594 0x55, 0xf0, 0x01, 0xf6,
11595 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11596 0x00, 0xec, 0x85, 0xf0,
11597 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11598 0x86, 0xf0, 0xb4, 0x00,
11599 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11600 0xaa, 0x18, 0x02, 0x80,
11601 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11602 0x00, 0x57, 0x01, 0xea,
11603 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11604 0x03, 0xe6, 0xb6, 0x00,
11605 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11606 0x02, 0x4a, 0xb9, 0x54,
11607 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11608 0x3e, 0x00, 0x80, 0x00,
11609 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11610 0x74, 0x01, 0x76, 0x01,
11611 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11612 0x4c, 0x1c, 0xbb, 0x55,
11613 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11614 0x03, 0xf7, 0x06, 0xf7,
11615 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11616 0x30, 0x13, 0x64, 0x15,
11617 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11618 0x04, 0xea, 0x5d, 0xf0,
11619 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11620 0xcc, 0x00, 0x20, 0x01,
11621 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11622 0x40, 0x13, 0x30, 0x1c,
11623 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11624 0x59, 0xf0, 0xa7, 0xf0,
11625 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11626 0xa4, 0x00, 0xb5, 0x00,
11627 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11628 0x14, 0x0e, 0x02, 0x10,
11629 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11630 0x10, 0x15, 0x14, 0x15,
11631 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11632 0x91, 0x44, 0x0a, 0x45,
11633 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11634 0x83, 0x59, 0x05, 0xe6,
11635 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11636 0x02, 0xfa, 0x03, 0xfa,
11637 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11638 0x9e, 0x00, 0xa8, 0x00,
11639 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11640 0x7a, 0x01, 0xc0, 0x01,
11641 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11642 0x69, 0x08, 0xba, 0x08,
11643 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11644 0xf1, 0x10, 0x06, 0x12,
11645 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11646 0x8a, 0x15, 0xc6, 0x17,
11647 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11648 0x0e, 0x47, 0x48, 0x47,
11649 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11650 0x14, 0x56, 0x77, 0x57,
11651 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11652 0xf0, 0x29, 0x02, 0xfe,
11653 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11654 0xfe, 0x80, 0x01, 0xff,
11655 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11656 0x00, 0xfe, 0x57, 0x24,
11657 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11658 0x00, 0x00, 0xff, 0x08,
11659 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11660 0xff, 0xff, 0xff, 0x0f,
11661 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11662 0xfe, 0x04, 0xf7, 0xcf,
11663 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11664 0x0b, 0x3c, 0x2a, 0xfe,
11665 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11666 0xfe, 0xf0, 0x01, 0xfe,
11667 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11668 0x02, 0xfe, 0xd4, 0x0c,
11669 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11670 0x1c, 0x05, 0xfe, 0xa6,
11671 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11672 0xf0, 0xfe, 0x86, 0x02,
11673 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11674 0xfe, 0x46, 0xf0, 0xfe,
11675 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11676 0x44, 0x02, 0xfe, 0x44,
11677 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11678 0xa0, 0x17, 0x06, 0x18,
11679 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11680 0x1e, 0x1c, 0xfe, 0xe9,
11681 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11682 0x0a, 0x6b, 0x01, 0x9e,
11683 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11684 0x01, 0x82, 0xfe, 0xbd,
11685 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11686 0x58, 0x1c, 0x17, 0x06,
11687 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11688 0xfe, 0x94, 0x02, 0xfe,
11689 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11690 0x01, 0xfe, 0x54, 0x0f,
11691 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11692 0x69, 0x10, 0x17, 0x06,
11693 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11694 0xf6, 0xc7, 0x01, 0xfe,
11695 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11696 0x02, 0x29, 0x0a, 0x40,
11697 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11698 0x58, 0x0a, 0x99, 0x01,
11699 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11700 0x2a, 0x46, 0xfe, 0x02,
11701 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11702 0x01, 0xfe, 0x07, 0x4b,
11703 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11704 0xfe, 0x56, 0x03, 0xfe,
11705 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11706 0xfe, 0x9f, 0xf0, 0xfe,
11707 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11708 0x1c, 0xeb, 0x09, 0x04,
11709 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11710 0x01, 0x0e, 0xac, 0x75,
11711 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11712 0xfe, 0x82, 0xf0, 0xfe,
11713 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11714 0x32, 0x1f, 0xfe, 0xb4,
11715 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11716 0x0a, 0xf0, 0xfe, 0x7a,
11717 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11718 0x01, 0x33, 0x8f, 0xfe,
11719 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11720 0xf7, 0xfe, 0x48, 0x1c,
11721 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11722 0x0a, 0xca, 0x01, 0x0e,
11723 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11724 0x2c, 0x01, 0x33, 0x8f,
11725 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11726 0xfe, 0x3c, 0x04, 0x1f,
11727 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11728 0x12, 0x2b, 0xff, 0x02,
11729 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11730 0x22, 0x30, 0x2e, 0xd5,
11731 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11732 0xfe, 0x4c, 0x54, 0x64,
11733 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11734 0xfe, 0x2a, 0x13, 0x2f,
11735 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11736 0xd3, 0xfa, 0xef, 0x86,
11737 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11738 0x1d, 0xfe, 0x1c, 0x12,
11739 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11740 0x70, 0x0c, 0x02, 0x22,
11741 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11742 0x01, 0x33, 0x02, 0x29,
11743 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11744 0x80, 0xfe, 0x31, 0xe4,
11745 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11746 0xfe, 0x70, 0x12, 0x49,
11747 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11748 0x80, 0x05, 0xfe, 0x31,
11749 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11750 0x28, 0xfe, 0x42, 0x12,
11751 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11752 0x11, 0xfe, 0xe3, 0x00,
11753 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11754 0x64, 0x05, 0x83, 0x24,
11755 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11756 0x09, 0x48, 0x01, 0x08,
11757 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11758 0x86, 0x24, 0x06, 0x12,
11759 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11760 0x01, 0xa7, 0x14, 0x92,
11761 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11762 0x02, 0x22, 0x05, 0xfe,
11763 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11764 0x47, 0x01, 0xa7, 0x26,
11765 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11766 0x01, 0xfe, 0xaa, 0x14,
11767 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11768 0x05, 0x50, 0xb4, 0x0c,
11769 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11770 0x13, 0x01, 0xfe, 0x14,
11771 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11772 0xff, 0x02, 0x00, 0x57,
11773 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11774 0x72, 0x06, 0x49, 0x04,
11775 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11776 0x06, 0x11, 0x9a, 0x01,
11777 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11778 0x01, 0xa7, 0xec, 0x72,
11779 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11780 0xfe, 0x0a, 0xf0, 0xfe,
11781 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11782 0x8d, 0x81, 0x02, 0x22,
11783 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11784 0x01, 0x08, 0x15, 0x00,
11785 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11786 0x00, 0x02, 0xfe, 0x32,
11787 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11788 0xfe, 0x1b, 0x00, 0x01,
11789 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11790 0x08, 0x15, 0x06, 0x01,
11791 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11792 0x9a, 0x81, 0x4b, 0x1d,
11793 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11794 0x45, 0xfe, 0x32, 0x12,
11795 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11796 0xfe, 0x32, 0x07, 0x8d,
11797 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11798 0x06, 0x15, 0x19, 0x02,
11799 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11800 0x90, 0x77, 0xfe, 0xca,
11801 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11802 0x10, 0xfe, 0x0e, 0x12,
11803 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11804 0x83, 0xe7, 0xc4, 0xa1,
11805 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11806 0x40, 0x12, 0x58, 0x01,
11807 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11808 0x51, 0x83, 0xfb, 0xfe,
11809 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11810 0xfe, 0x40, 0x50, 0xfe,
11811 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11812 0xfe, 0x2a, 0x12, 0xfe,
11813 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11814 0x85, 0x01, 0xa8, 0xfe,
11815 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11816 0x18, 0x57, 0xfb, 0xfe,
11817 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11818 0x0c, 0x39, 0x18, 0x3a,
11819 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11820 0x11, 0x65, 0xfe, 0x48,
11821 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11822 0xdd, 0xb8, 0xfe, 0x80,
11823 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11824 0xfe, 0x7a, 0x08, 0x8d,
11825 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11826 0x10, 0x61, 0x04, 0x06,
11827 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11828 0x12, 0xfe, 0x2e, 0x1c,
11829 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11830 0x52, 0x12, 0xfe, 0x2c,
11831 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11832 0x08, 0xfe, 0x8a, 0x10,
11833 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11834 0x24, 0x0a, 0xab, 0xfe,
11835 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11836 0x1c, 0x12, 0xb5, 0xfe,
11837 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11838 0x1c, 0x06, 0x16, 0x9d,
11839 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11840 0x14, 0x92, 0x01, 0x33,
11841 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11842 0xfe, 0x74, 0x18, 0x1c,
11843 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11844 0x01, 0xe6, 0x1e, 0x27,
11845 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11846 0x09, 0x04, 0x6a, 0xfe,
11847 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11848 0xfe, 0x83, 0x80, 0xfe,
11849 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11850 0x27, 0xfe, 0x40, 0x59,
11851 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11852 0x7c, 0xbe, 0x54, 0xbf,
11853 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11854 0x79, 0x56, 0x68, 0x57,
11855 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11856 0xa2, 0x23, 0x0c, 0x7b,
11857 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11858 0x16, 0xd7, 0x79, 0x39,
11859 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11860 0xfe, 0x10, 0x58, 0xfe,
11861 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
11862 0x19, 0x16, 0xd7, 0x09,
11863 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
11864 0xfe, 0x10, 0x90, 0xfe,
11865 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
11866 0x11, 0x9b, 0x09, 0x04,
11867 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
11868 0xfe, 0x0c, 0x58, 0xfe,
11869 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
11870 0x0b, 0xfe, 0x1a, 0x12,
11871 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
11872 0x14, 0x7a, 0x01, 0x33,
11873 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
11874 0xfe, 0xed, 0x19, 0xbf,
11875 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
11876 0x34, 0xfe, 0x74, 0x10,
11877 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
11878 0x84, 0x05, 0xcb, 0x1c,
11879 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
11880 0xf0, 0xfe, 0xc4, 0x0a,
11881 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
11882 0xce, 0xf0, 0xfe, 0xca,
11883 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
11884 0x22, 0x00, 0x02, 0x5a,
11885 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
11886 0xfe, 0xd0, 0xf0, 0xfe,
11887 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
11888 0x4c, 0xfe, 0x10, 0x10,
11889 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
11890 0x2a, 0x13, 0xfe, 0x4e,
11891 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
11892 0x16, 0x32, 0x2a, 0x73,
11893 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
11894 0x32, 0x8c, 0xfe, 0x48,
11895 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
11896 0xdb, 0x10, 0x11, 0xfe,
11897 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
11898 0x22, 0x30, 0x2e, 0xd8,
11899 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
11900 0x45, 0x0f, 0xfe, 0x42,
11901 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
11902 0x09, 0x04, 0x0b, 0xfe,
11903 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
11904 0x00, 0x21, 0xfe, 0xa6,
11905 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
11906 0xfe, 0xe2, 0x10, 0x01,
11907 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
11908 0x01, 0x6f, 0x02, 0x29,
11909 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
11910 0x01, 0x86, 0x3e, 0x0b,
11911 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
11912 0x3e, 0x0b, 0x0f, 0xfe,
11913 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
11914 0xe8, 0x59, 0x11, 0x2d,
11915 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
11916 0x04, 0x0b, 0x84, 0x3e,
11917 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
11918 0x09, 0x04, 0x1b, 0xfe,
11919 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
11920 0x1c, 0x1c, 0xfe, 0x9d,
11921 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
11922 0xfe, 0x15, 0x00, 0xfe,
11923 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
11924 0x0f, 0xfe, 0x47, 0x00,
11925 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
11926 0xab, 0x70, 0x05, 0x6b,
11927 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
11928 0x1c, 0x42, 0x59, 0x01,
11929 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
11930 0x00, 0x37, 0x97, 0x01,
11931 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
11932 0x1d, 0xfe, 0xce, 0x45,
11933 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
11934 0x57, 0x05, 0x51, 0xfe,
11935 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
11936 0x46, 0x09, 0x04, 0x1d,
11937 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
11938 0x99, 0x01, 0x0e, 0xfe,
11939 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
11940 0xfe, 0xee, 0x14, 0xee,
11941 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
11942 0x13, 0x02, 0x29, 0x1e,
11943 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
11944 0xce, 0x1e, 0x2d, 0x47,
11945 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
11946 0x12, 0x4d, 0x01, 0xfe,
11947 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
11948 0xf0, 0x0d, 0xfe, 0x02,
11949 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
11950 0xf6, 0xfe, 0x34, 0x01,
11951 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
11952 0xaf, 0xfe, 0x02, 0xea,
11953 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
11954 0x05, 0xfe, 0x38, 0x01,
11955 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
11956 0x0c, 0xfe, 0x62, 0x01,
11957 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
11958 0x03, 0x23, 0x03, 0x1e,
11959 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
11960 0x71, 0x13, 0xfe, 0x24,
11961 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
11962 0xdc, 0xfe, 0x73, 0x57,
11963 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
11964 0x80, 0x5d, 0x03, 0xfe,
11965 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
11966 0x75, 0x03, 0x09, 0x04,
11967 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
11968 0xfe, 0x1e, 0x80, 0xe1,
11969 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
11970 0x90, 0xa3, 0xfe, 0x3c,
11971 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
11972 0x16, 0x2f, 0x07, 0x2d,
11973 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
11974 0xe8, 0x11, 0xfe, 0xe9,
11975 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
11976 0x1e, 0x1c, 0xfe, 0x14,
11977 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
11978 0x09, 0x04, 0x4f, 0xfe,
11979 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
11980 0x40, 0x12, 0x20, 0x63,
11981 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
11982 0x1c, 0x05, 0xfe, 0xac,
11983 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
11984 0xfe, 0xb0, 0x00, 0xfe,
11985 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
11986 0x24, 0x69, 0x12, 0xc9,
11987 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
11988 0x90, 0x4d, 0xfe, 0x91,
11989 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
11990 0xfe, 0x90, 0x4d, 0xfe,
11991 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
11992 0x46, 0x1e, 0x20, 0xed,
11993 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
11994 0x70, 0xfe, 0x14, 0x1c,
11995 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
11996 0xfe, 0x07, 0xe6, 0x1d,
11997 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
11998 0xfa, 0xef, 0xfe, 0x42,
11999 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
12000 0xfe, 0x36, 0x12, 0xf0,
12001 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
12002 0x3d, 0x75, 0x07, 0x10,
12003 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
12004 0x10, 0x07, 0x7e, 0x45,
12005 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
12006 0xfe, 0x01, 0xec, 0x97,
12007 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
12008 0x27, 0x01, 0xda, 0xfe,
12009 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
12010 0xfe, 0x48, 0x12, 0x07,
12011 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
12012 0xfe, 0x3e, 0x11, 0x07,
12013 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
12014 0x11, 0x07, 0x19, 0xfe,
12015 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
12016 0x01, 0x08, 0x8c, 0x43,
12017 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
12018 0x7e, 0x02, 0x29, 0x2b,
12019 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
12020 0xfc, 0x10, 0x09, 0x04,
12021 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
12022 0xc6, 0x10, 0x1e, 0x58,
12023 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
12024 0x54, 0x18, 0x55, 0x23,
12025 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
12026 0xa5, 0xc0, 0x38, 0xc1,
12027 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
12028 0x05, 0xfa, 0x4e, 0xfe,
12029 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
12030 0x0c, 0x56, 0x18, 0x57,
12031 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
12032 0x00, 0x56, 0xfe, 0xa1,
12033 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
12034 0x58, 0xfe, 0x1f, 0x40,
12035 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
12036 0x31, 0x57, 0xfe, 0x44,
12037 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
12038 0x8a, 0x50, 0x05, 0x39,
12039 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
12040 0x12, 0xcd, 0x02, 0x5b,
12041 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
12042 0x2f, 0x07, 0x9b, 0x21,
12043 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
12044 0x39, 0x68, 0x3a, 0xfe,
12045 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
12046 0x51, 0xfe, 0x8e, 0x51,
12047 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
12048 0x01, 0x08, 0x25, 0x32,
12049 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
12050 0x3b, 0x02, 0x44, 0x01,
12051 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
12052 0x01, 0x08, 0x1f, 0xa2,
12053 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
12054 0x00, 0x28, 0x84, 0x49,
12055 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
12056 0x78, 0x3d, 0xfe, 0xda,
12057 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
12058 0x05, 0xc6, 0x28, 0x84,
12059 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
12060 0x14, 0xfe, 0x03, 0x17,
12061 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
12062 0xfe, 0xaa, 0x14, 0x02,
12063 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
12064 0x21, 0x44, 0x01, 0xfe,
12065 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
12066 0xfe, 0x4a, 0xf4, 0x0b,
12067 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
12068 0x85, 0x02, 0x5b, 0x05,
12069 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
12070 0xd8, 0x14, 0x02, 0x5c,
12071 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
12072 0x01, 0x08, 0x23, 0x72,
12073 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
12074 0x12, 0x5e, 0x2b, 0x01,
12075 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
12076 0x1c, 0xfe, 0xff, 0x7f,
12077 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
12078 0x57, 0x48, 0x8b, 0x1c,
12079 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
12080 0x00, 0x57, 0x48, 0x8b,
12081 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
12082 0x03, 0x0a, 0x50, 0x01,
12083 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
12084 0x54, 0xfe, 0x00, 0xf4,
12085 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
12086 0x03, 0x7c, 0x63, 0x27,
12087 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
12088 0xfe, 0x82, 0x4a, 0xfe,
12089 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
12090 0x42, 0x48, 0x5f, 0x60,
12091 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
12092 0x1f, 0xfe, 0xa2, 0x14,
12093 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
12094 0xcc, 0x12, 0x49, 0x04,
12095 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
12096 0xe8, 0x13, 0x3b, 0x13,
12097 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
12098 0xa1, 0xff, 0x02, 0x83,
12099 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
12100 0x13, 0x06, 0xfe, 0x56,
12101 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
12102 0x64, 0x00, 0x17, 0x93,
12103 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
12104 0xc8, 0x00, 0x8e, 0xe4,
12105 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
12106 0x01, 0xba, 0xfe, 0x4e,
12107 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
12108 0xfe, 0x60, 0x14, 0xfe,
12109 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
12110 0xfe, 0x22, 0x13, 0x1c,
12111 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
12112 0xfe, 0x9c, 0x14, 0xb7,
12113 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
12114 0xfe, 0x9c, 0x14, 0xb7,
12115 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
12116 0xfe, 0xb4, 0x56, 0xfe,
12117 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
12118 0xe5, 0x15, 0x0b, 0x01,
12119 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
12120 0x49, 0x01, 0x08, 0x03,
12121 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
12122 0x15, 0x06, 0x01, 0x08,
12123 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
12124 0x4a, 0x01, 0x08, 0x03,
12125 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
12126 0xfe, 0x49, 0xf4, 0x00,
12127 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
12128 0x08, 0x2f, 0x07, 0xfe,
12129 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
12130 0x01, 0x43, 0x1e, 0xcd,
12131 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
12132 0xed, 0x88, 0x07, 0x10,
12133 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
12134 0x80, 0x01, 0x0e, 0x88,
12135 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
12136 0x88, 0x03, 0x0a, 0x42,
12137 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
12138 0xfe, 0x80, 0x80, 0xf2,
12139 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
12140 0x01, 0x82, 0x03, 0x17,
12141 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
12142 0xfe, 0x24, 0x1c, 0xfe,
12143 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
12144 0x91, 0x1d, 0x66, 0xfe,
12145 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
12146 0xda, 0x10, 0x17, 0x10,
12147 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
12148 0x05, 0xfe, 0x66, 0x01,
12149 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
12150 0xfe, 0x3c, 0x50, 0x66,
12151 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
12152 0x40, 0x16, 0xfe, 0xb6,
12153 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
12154 0x10, 0x71, 0xfe, 0x83,
12155 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
12156 0xfe, 0x62, 0x16, 0xfe,
12157 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
12158 0xfe, 0x98, 0xe7, 0x00,
12159 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
12160 0xfe, 0x30, 0xbc, 0xfe,
12161 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12162 0xc5, 0x90, 0xfe, 0x9a,
12163 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
12164 0x42, 0x10, 0xfe, 0x02,
12165 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
12166 0xfe, 0x1d, 0xf7, 0x4f,
12167 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
12168 0x47, 0xfe, 0x83, 0x58,
12169 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
12170 0xfe, 0xdd, 0x00, 0x63,
12171 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
12172 0x06, 0x37, 0x95, 0xa9,
12173 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
12174 0x18, 0x1c, 0x1a, 0x5d,
12175 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
12176 0xe1, 0x10, 0x78, 0x2c,
12177 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
12178 0x13, 0x3c, 0x8a, 0x0a,
12179 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
12180 0xe3, 0xfe, 0x00, 0xcc,
12181 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
12182 0x0e, 0xf2, 0x01, 0x6f,
12183 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
12184 0xf6, 0xfe, 0xd6, 0xf0,
12185 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
12186 0x15, 0x00, 0x59, 0x76,
12187 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
12188 0x11, 0x2d, 0x01, 0x6f,
12189 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
12190 0xc8, 0xfe, 0x48, 0x55,
12191 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
12192 0x99, 0x01, 0x0e, 0xf0,
12193 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
12194 0x75, 0x03, 0x0a, 0x42,
12195 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
12196 0x0e, 0x73, 0x75, 0x03,
12197 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
12198 0xfe, 0x3a, 0x45, 0x5b,
12199 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
12200 0xfe, 0x02, 0xe6, 0x1b,
12201 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
12202 0xfe, 0x94, 0x00, 0xfe,
12203 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
12204 0xe6, 0x2c, 0xfe, 0x4e,
12205 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
12206 0x03, 0x07, 0x7a, 0xfe,
12207 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12208 0x07, 0x1b, 0xfe, 0x5a,
12209 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
12210 0x24, 0x2c, 0xdc, 0x07,
12211 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
12212 0x9f, 0xad, 0x03, 0x14,
12213 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
12214 0x03, 0x25, 0xfe, 0xca,
12215 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
12216 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012217};
12218
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012219static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
12220static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012221
12222/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012223static unsigned char _adv_asc38C0800_buf[] = {
12224 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
12225 0x01, 0x00, 0x48, 0xe4,
12226 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
12227 0x1c, 0x0f, 0x00, 0xf6,
12228 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
12229 0x09, 0xe7, 0x55, 0xf0,
12230 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
12231 0x18, 0xf4, 0x08, 0x00,
12232 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
12233 0x86, 0xf0, 0xb1, 0xf0,
12234 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
12235 0x3c, 0x00, 0xbb, 0x00,
12236 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
12237 0xba, 0x13, 0x18, 0x40,
12238 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
12239 0x6e, 0x01, 0x74, 0x01,
12240 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
12241 0xc0, 0x00, 0x01, 0x01,
12242 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
12243 0x08, 0x12, 0x02, 0x4a,
12244 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
12245 0x5d, 0xf0, 0x02, 0xfa,
12246 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
12247 0x68, 0x01, 0x6a, 0x01,
12248 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
12249 0x06, 0x13, 0x4c, 0x1c,
12250 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
12251 0x0f, 0x00, 0x47, 0x00,
12252 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
12253 0x4e, 0x1c, 0x10, 0x44,
12254 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
12255 0x05, 0x00, 0x34, 0x00,
12256 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
12257 0x42, 0x0c, 0x12, 0x0f,
12258 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
12259 0x00, 0x4e, 0x42, 0x54,
12260 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
12261 0x59, 0xf0, 0xb8, 0xf0,
12262 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
12263 0x19, 0x00, 0x33, 0x00,
12264 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
12265 0xe7, 0x00, 0xe2, 0x03,
12266 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
12267 0x12, 0x13, 0x24, 0x14,
12268 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
12269 0x36, 0x1c, 0x08, 0x44,
12270 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
12271 0x3a, 0x55, 0x83, 0x55,
12272 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
12273 0x0c, 0xf0, 0x04, 0xf8,
12274 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
12275 0xa8, 0x00, 0xaa, 0x00,
12276 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
12277 0xc4, 0x01, 0xc6, 0x01,
12278 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
12279 0x68, 0x08, 0x69, 0x08,
12280 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
12281 0xed, 0x10, 0xf1, 0x10,
12282 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
12283 0x1e, 0x13, 0x46, 0x14,
12284 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
12285 0xca, 0x18, 0xe6, 0x19,
12286 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
12287 0xf0, 0x2b, 0x02, 0xfe,
12288 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
12289 0xfe, 0x84, 0x01, 0xff,
12290 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12291 0x00, 0xfe, 0x57, 0x24,
12292 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
12293 0x00, 0x00, 0xff, 0x08,
12294 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12295 0xff, 0xff, 0xff, 0x11,
12296 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12297 0xfe, 0x04, 0xf7, 0xd6,
12298 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
12299 0x0a, 0x42, 0x2c, 0xfe,
12300 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
12301 0xfe, 0xf4, 0x01, 0xfe,
12302 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
12303 0x02, 0xfe, 0xc8, 0x0d,
12304 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
12305 0x1c, 0x03, 0xfe, 0xa6,
12306 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
12307 0xf0, 0xfe, 0x8a, 0x02,
12308 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
12309 0xfe, 0x46, 0xf0, 0xfe,
12310 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
12311 0x48, 0x02, 0xfe, 0x44,
12312 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
12313 0xaa, 0x18, 0x06, 0x14,
12314 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
12315 0x1e, 0x1c, 0xfe, 0xe9,
12316 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
12317 0x09, 0x70, 0x01, 0xa8,
12318 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
12319 0x01, 0x87, 0xfe, 0xbd,
12320 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
12321 0x58, 0x1c, 0x18, 0x06,
12322 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
12323 0xfe, 0x98, 0x02, 0xfe,
12324 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
12325 0x01, 0xfe, 0x48, 0x10,
12326 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
12327 0x69, 0x10, 0x18, 0x06,
12328 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
12329 0xf6, 0xce, 0x01, 0xfe,
12330 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
12331 0x82, 0x16, 0x02, 0x2b,
12332 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
12333 0xfe, 0x41, 0x58, 0x09,
12334 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
12335 0x82, 0x16, 0x02, 0x2b,
12336 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
12337 0xfe, 0x77, 0x57, 0xfe,
12338 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
12339 0xfe, 0x40, 0x1c, 0x1c,
12340 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
12341 0x03, 0xfe, 0x11, 0xf0,
12342 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
12343 0xfe, 0x11, 0x00, 0x02,
12344 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
12345 0x21, 0x22, 0xa3, 0xb7,
12346 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
12347 0x12, 0xd1, 0x1c, 0xd9,
12348 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
12349 0xfe, 0xe4, 0x00, 0x27,
12350 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
12351 0x06, 0xf0, 0xfe, 0xc8,
12352 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
12353 0x70, 0x28, 0x17, 0xfe,
12354 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
12355 0xf9, 0x2c, 0x99, 0x19,
12356 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
12357 0x74, 0x01, 0xaf, 0x8c,
12358 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
12359 0x8d, 0x51, 0x64, 0x79,
12360 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
12361 0xfe, 0x6a, 0x02, 0x02,
12362 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
12363 0xfe, 0x3c, 0x04, 0x3b,
12364 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
12365 0x00, 0x10, 0x01, 0x0b,
12366 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
12367 0xfe, 0x4c, 0x44, 0xfe,
12368 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
12369 0xda, 0x4f, 0x79, 0x2a,
12370 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
12371 0xfe, 0x2a, 0x13, 0x32,
12372 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
12373 0x54, 0x6b, 0xda, 0xfe,
12374 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
12375 0x08, 0x13, 0x32, 0x07,
12376 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
12377 0x08, 0x05, 0x06, 0x4d,
12378 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
12379 0x2d, 0x12, 0xfe, 0xe6,
12380 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
12381 0x02, 0x2b, 0xfe, 0x42,
12382 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12383 0xfe, 0x87, 0x80, 0xfe,
12384 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
12385 0x07, 0x19, 0xfe, 0x7c,
12386 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
12387 0x17, 0xfe, 0x90, 0x05,
12388 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
12389 0xa0, 0x00, 0x28, 0xfe,
12390 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
12391 0x34, 0xfe, 0x89, 0x48,
12392 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
12393 0x12, 0xfe, 0xe3, 0x00,
12394 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
12395 0x70, 0x05, 0x88, 0x25,
12396 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
12397 0x09, 0x48, 0xff, 0x02,
12398 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
12399 0x08, 0x53, 0x05, 0xcb,
12400 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
12401 0x05, 0x1b, 0xfe, 0x22,
12402 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
12403 0x0d, 0x00, 0x01, 0x36,
12404 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
12405 0x03, 0x5c, 0x28, 0xfe,
12406 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
12407 0x05, 0x1f, 0xfe, 0x02,
12408 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
12409 0x01, 0x4b, 0x12, 0xfe,
12410 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
12411 0x12, 0x03, 0x45, 0x28,
12412 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
12413 0x43, 0x48, 0xc4, 0xcc,
12414 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
12415 0x6e, 0x41, 0x01, 0xb2,
12416 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
12417 0xfe, 0xcc, 0x15, 0x1d,
12418 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
12419 0x45, 0xc1, 0x0c, 0x45,
12420 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
12421 0xe2, 0x00, 0x27, 0xdb,
12422 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
12423 0xfe, 0x06, 0xf0, 0xfe,
12424 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
12425 0x16, 0x19, 0x01, 0x0b,
12426 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
12427 0xfe, 0x99, 0xa4, 0x01,
12428 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
12429 0x12, 0x08, 0x05, 0x1a,
12430 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
12431 0x0b, 0x16, 0x00, 0x01,
12432 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
12433 0xe2, 0x6c, 0x58, 0xbe,
12434 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
12435 0xfe, 0x09, 0x6f, 0xba,
12436 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
12437 0xfe, 0x54, 0x07, 0x1c,
12438 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
12439 0x07, 0x02, 0x24, 0x01,
12440 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
12441 0x2c, 0x90, 0xfe, 0xae,
12442 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
12443 0x37, 0x22, 0x20, 0x07,
12444 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
12445 0xfe, 0x06, 0x10, 0xfe,
12446 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
12447 0x37, 0x01, 0xb3, 0xb8,
12448 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
12449 0x50, 0xfe, 0x44, 0x51,
12450 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
12451 0x14, 0x5f, 0xfe, 0x0c,
12452 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
12453 0x14, 0x3e, 0xfe, 0x4a,
12454 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
12455 0x90, 0x0c, 0x60, 0x14,
12456 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
12457 0xfe, 0x44, 0x90, 0xfe,
12458 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
12459 0x0c, 0x5e, 0x14, 0x5f,
12460 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
12461 0x14, 0x3c, 0x21, 0x0c,
12462 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
12463 0x27, 0xdd, 0xfe, 0x9e,
12464 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
12465 0x9a, 0x08, 0xc6, 0xfe,
12466 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
12467 0x95, 0x86, 0x02, 0x24,
12468 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
12469 0x06, 0xfe, 0x10, 0x12,
12470 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
12471 0x1c, 0x02, 0xfe, 0x18,
12472 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
12473 0x2c, 0x1c, 0xfe, 0xaa,
12474 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
12475 0xde, 0x09, 0xfe, 0xb7,
12476 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
12477 0xfe, 0xf1, 0x18, 0xfe,
12478 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
12479 0x14, 0x59, 0xfe, 0x95,
12480 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
12481 0xfe, 0xf0, 0x08, 0xb5,
12482 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
12483 0x0b, 0xb6, 0xfe, 0xbf,
12484 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
12485 0x12, 0xc2, 0xfe, 0xd2,
12486 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
12487 0x06, 0x17, 0x85, 0xc5,
12488 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
12489 0x9d, 0x01, 0x36, 0x10,
12490 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
12491 0x98, 0x80, 0xfe, 0x19,
12492 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
12493 0xfe, 0x44, 0x54, 0xbe,
12494 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
12495 0x02, 0x4a, 0x08, 0x05,
12496 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
12497 0x9c, 0x3c, 0xfe, 0x6c,
12498 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
12499 0x3b, 0x40, 0x03, 0x49,
12500 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
12501 0x8f, 0xfe, 0xe3, 0x54,
12502 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
12503 0xda, 0x09, 0xfe, 0x8b,
12504 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
12505 0x0a, 0x3a, 0x49, 0x3b,
12506 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
12507 0xad, 0xfe, 0x01, 0x59,
12508 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
12509 0x49, 0x8f, 0xfe, 0xe3,
12510 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
12511 0x4a, 0x3a, 0x49, 0x3b,
12512 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
12513 0x02, 0x4a, 0x08, 0x05,
12514 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
12515 0xb7, 0xfe, 0x03, 0xa1,
12516 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12517 0xfe, 0x86, 0x91, 0x6a,
12518 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12519 0x61, 0x0c, 0x7f, 0x14,
12520 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12521 0x9b, 0x2e, 0x9c, 0x3c,
12522 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12523 0xfa, 0x3c, 0x01, 0xef,
12524 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12525 0xe4, 0x08, 0x05, 0x1f,
12526 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12527 0x03, 0x5e, 0x29, 0x5f,
12528 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12529 0xf4, 0x09, 0x08, 0x05,
12530 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12531 0x81, 0x50, 0xfe, 0x10,
12532 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12533 0x08, 0x09, 0x12, 0xa6,
12534 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12535 0x08, 0x09, 0xfe, 0x0c,
12536 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12537 0x08, 0x05, 0x0a, 0xfe,
12538 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12539 0xf0, 0xe2, 0x15, 0x7e,
12540 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12541 0x57, 0x3d, 0xfe, 0xed,
12542 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12543 0x00, 0xff, 0x35, 0xfe,
12544 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12545 0x1e, 0x19, 0x8a, 0x03,
12546 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12547 0xfe, 0xd1, 0xf0, 0xfe,
12548 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12549 0x10, 0xfe, 0xce, 0xf0,
12550 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12551 0x10, 0xfe, 0x22, 0x00,
12552 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12553 0x02, 0x65, 0xfe, 0xd0,
12554 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12555 0x0b, 0x10, 0x58, 0xfe,
12556 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12557 0x12, 0x00, 0x2c, 0x0f,
12558 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12559 0x0c, 0xbc, 0x17, 0x34,
12560 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12561 0x0c, 0x1c, 0x34, 0x94,
12562 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12563 0x4b, 0xfe, 0xdb, 0x10,
12564 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12565 0x89, 0xf0, 0x24, 0x33,
12566 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12567 0x33, 0x31, 0xdf, 0xbc,
12568 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12569 0x17, 0xfe, 0x2c, 0x0d,
12570 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12571 0x12, 0x55, 0xfe, 0x28,
12572 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12573 0x44, 0xfe, 0x28, 0x00,
12574 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12575 0x0f, 0x64, 0x12, 0x2f,
12576 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12577 0x0a, 0xfe, 0xb4, 0x10,
12578 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12579 0xfe, 0x34, 0x46, 0xac,
12580 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12581 0x37, 0x01, 0xf5, 0x01,
12582 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12583 0xfe, 0x2e, 0x03, 0x08,
12584 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12585 0x1a, 0xfe, 0x58, 0x12,
12586 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12587 0xfe, 0x50, 0x0d, 0xfe,
12588 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12589 0xfe, 0xa9, 0x10, 0x10,
12590 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12591 0xfe, 0x13, 0x00, 0xfe,
12592 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12593 0x24, 0x00, 0x8c, 0xb5,
12594 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12595 0xfe, 0x9d, 0x41, 0xfe,
12596 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12597 0xb4, 0x15, 0xfe, 0x31,
12598 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12599 0xec, 0xd0, 0xfc, 0x44,
12600 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12601 0x4b, 0x91, 0xfe, 0x75,
12602 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12603 0x0e, 0xfe, 0x44, 0x48,
12604 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12605 0xfe, 0x41, 0x58, 0x09,
12606 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12607 0x2e, 0x03, 0x09, 0x5d,
12608 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12609 0xce, 0x47, 0xfe, 0xad,
12610 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12611 0x59, 0x13, 0x9f, 0x13,
12612 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12613 0xe0, 0x0e, 0x0f, 0x06,
12614 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12615 0x3a, 0x01, 0x56, 0xfe,
12616 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12617 0x20, 0x4f, 0xfe, 0x05,
12618 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12619 0x48, 0xf4, 0x0d, 0xfe,
12620 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12621 0x15, 0x1a, 0x39, 0xa0,
12622 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12623 0x0c, 0xfe, 0x60, 0x01,
12624 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12625 0x06, 0x13, 0x2f, 0x12,
12626 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12627 0x22, 0x9f, 0xb7, 0x13,
12628 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12629 0xa0, 0xb4, 0xfe, 0xd9,
12630 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12631 0xc3, 0xfe, 0x03, 0xdc,
12632 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12633 0xfe, 0x00, 0xcc, 0x04,
12634 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12635 0xfe, 0x1c, 0x80, 0x07,
12636 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12637 0xfe, 0x0c, 0x90, 0xfe,
12638 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12639 0x0a, 0xfe, 0x3c, 0x50,
12640 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12641 0x16, 0x08, 0x05, 0x1b,
12642 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12643 0xfe, 0x2c, 0x13, 0x01,
12644 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12645 0x0c, 0xfe, 0x64, 0x01,
12646 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12647 0x80, 0x8d, 0xfe, 0x01,
12648 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12649 0x22, 0x20, 0xfb, 0x79,
12650 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12651 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012653 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12654 0xb2, 0x00, 0xfe, 0x09,
12655 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12656 0x45, 0x0f, 0x46, 0x52,
12657 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12658 0x0f, 0x44, 0x11, 0x0f,
12659 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12660 0x25, 0x11, 0x13, 0x20,
12661 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12662 0x56, 0xfe, 0xd6, 0xf0,
12663 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12664 0x18, 0x1c, 0x04, 0x42,
12665 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12666 0xf5, 0x13, 0x04, 0x01,
12667 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12668 0x13, 0x32, 0x07, 0x2f,
12669 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12670 0x41, 0x48, 0xfe, 0x45,
12671 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12672 0x07, 0x11, 0xac, 0x09,
12673 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12674 0x82, 0x4e, 0xfe, 0x14,
12675 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12676 0xfe, 0x01, 0xec, 0xa2,
12677 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12678 0x2a, 0x01, 0xe3, 0xfe,
12679 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12680 0xfe, 0x48, 0x12, 0x07,
12681 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12682 0xfe, 0x32, 0x12, 0x07,
12683 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12684 0x1f, 0xfe, 0x12, 0x12,
12685 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12686 0x94, 0x4b, 0x04, 0x2d,
12687 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12688 0x32, 0x07, 0xa6, 0xfe,
12689 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12690 0x5a, 0xfe, 0x72, 0x12,
12691 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12692 0xfe, 0x26, 0x13, 0x03,
12693 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12694 0x0c, 0x7f, 0x0c, 0x80,
12695 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12696 0x3c, 0xfe, 0x04, 0x55,
12697 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12698 0x91, 0x10, 0x03, 0x3f,
12699 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12700 0x88, 0x9b, 0x2e, 0x9c,
12701 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12702 0x56, 0x0c, 0x5e, 0x14,
12703 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12704 0x03, 0x60, 0x29, 0x61,
12705 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12706 0x50, 0xfe, 0xc6, 0x50,
12707 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12708 0x29, 0x3e, 0xfe, 0x40,
12709 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12710 0x2d, 0x01, 0x0b, 0x1d,
12711 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12712 0x72, 0x01, 0xaf, 0x1e,
12713 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12714 0x0a, 0x55, 0x35, 0xfe,
12715 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12716 0x02, 0x72, 0xfe, 0x19,
12717 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12718 0x1d, 0xe8, 0x33, 0x31,
12719 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12720 0x0b, 0x1c, 0x34, 0x1d,
12721 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12722 0x33, 0x31, 0xfe, 0xe8,
12723 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12724 0x05, 0x1f, 0x35, 0xa9,
12725 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12726 0x14, 0x01, 0xaf, 0x8c,
12727 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12728 0x03, 0x45, 0x28, 0x35,
12729 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12730 0x03, 0x5c, 0xc1, 0x0c,
12731 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12732 0x89, 0x01, 0x0b, 0x1c,
12733 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12734 0xfe, 0x42, 0x58, 0xf1,
12735 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12736 0xf4, 0x06, 0xea, 0x32,
12737 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12738 0x01, 0x0b, 0x26, 0x89,
12739 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12740 0x26, 0xfe, 0xd4, 0x13,
12741 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12742 0x13, 0x1c, 0xfe, 0xd0,
12743 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12744 0x0f, 0x71, 0xff, 0x02,
12745 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12746 0x00, 0x5c, 0x04, 0x0f,
12747 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12748 0xfe, 0x00, 0x5c, 0x04,
12749 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12750 0x02, 0x00, 0x57, 0x52,
12751 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12752 0x87, 0x04, 0xfe, 0x03,
12753 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12754 0xfe, 0x00, 0x7d, 0xfe,
12755 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12756 0x14, 0x5f, 0x57, 0x3f,
12757 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12758 0x5a, 0x8d, 0x04, 0x01,
12759 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12760 0xfe, 0x96, 0x15, 0x33,
12761 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12762 0x0a, 0xfe, 0xc1, 0x59,
12763 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12764 0x21, 0x69, 0x1a, 0xee,
12765 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12766 0x30, 0xfe, 0x78, 0x10,
12767 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12768 0x98, 0xfe, 0x30, 0x00,
12769 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12770 0x98, 0xfe, 0x64, 0x00,
12771 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12772 0x10, 0x69, 0x06, 0xfe,
12773 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12774 0x18, 0x59, 0x0f, 0x06,
12775 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12776 0x43, 0xf4, 0x9f, 0xfe,
12777 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12778 0x9e, 0xfe, 0xf3, 0x10,
12779 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12780 0x17, 0xfe, 0x4d, 0xe4,
12781 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12782 0x17, 0xfe, 0x4d, 0xe4,
12783 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12784 0xf4, 0x00, 0xe9, 0x91,
12785 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12786 0x04, 0x16, 0x06, 0x01,
12787 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12788 0x0b, 0x26, 0xf3, 0x76,
12789 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12790 0x16, 0x19, 0x01, 0x0b,
12791 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12792 0x0b, 0x26, 0xb1, 0x76,
12793 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12794 0xfe, 0x48, 0x13, 0xb8,
12795 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12796 0xec, 0xfe, 0x27, 0x01,
12797 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12798 0x07, 0xfe, 0xe3, 0x00,
12799 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12800 0x22, 0xd4, 0x07, 0x06,
12801 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12802 0x07, 0x11, 0xae, 0x09,
12803 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12804 0x0e, 0x8e, 0xfe, 0x80,
12805 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12806 0x09, 0x48, 0x01, 0x0e,
12807 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12808 0x80, 0xfe, 0x80, 0x4c,
12809 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12810 0x09, 0x5d, 0x01, 0x87,
12811 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12812 0x19, 0xde, 0xfe, 0x24,
12813 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12814 0x17, 0xad, 0x9a, 0x1b,
12815 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12816 0x16, 0xfe, 0xda, 0x10,
12817 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12818 0x18, 0x58, 0x03, 0xfe,
12819 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12820 0xf4, 0x06, 0xfe, 0x3c,
12821 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12822 0x97, 0xfe, 0x38, 0x17,
12823 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12824 0x10, 0x18, 0x11, 0x75,
12825 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12826 0x2e, 0x97, 0xfe, 0x5a,
12827 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12828 0xfe, 0x98, 0xe7, 0x00,
12829 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12830 0xfe, 0x30, 0xbc, 0xfe,
12831 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12832 0xcb, 0x97, 0xfe, 0x92,
12833 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12834 0x42, 0x10, 0xfe, 0x02,
12835 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12836 0x03, 0xa1, 0xfe, 0x1d,
12837 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12838 0x9a, 0x5b, 0x41, 0xfe,
12839 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12840 0x11, 0x12, 0xfe, 0xdd,
12841 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12842 0x17, 0x15, 0x06, 0x39,
12843 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12844 0xfe, 0x7e, 0x18, 0x1e,
12845 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12846 0x12, 0xfe, 0xe1, 0x10,
12847 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12848 0x13, 0x42, 0x92, 0x09,
12849 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12850 0xf0, 0xfe, 0x00, 0xcc,
12851 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12852 0x0e, 0xfe, 0x80, 0x4c,
12853 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12854 0x24, 0x12, 0xfe, 0x14,
12855 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12856 0xe7, 0x0a, 0x10, 0xfe,
12857 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12858 0x08, 0x54, 0x1b, 0x37,
12859 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12860 0x90, 0x3a, 0xce, 0x3b,
12861 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
12862 0x13, 0xa3, 0x04, 0x09,
12863 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
12864 0x44, 0x17, 0xfe, 0xe8,
12865 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
12866 0x5d, 0x01, 0xa8, 0x09,
12867 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
12868 0x1c, 0x19, 0x03, 0xfe,
12869 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
12870 0x6b, 0xfe, 0x2e, 0x19,
12871 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
12872 0xfe, 0x0b, 0x00, 0x6b,
12873 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
12874 0x08, 0x10, 0x03, 0xfe,
12875 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
12876 0x04, 0x68, 0x54, 0xe7,
12877 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
12878 0x1a, 0xf4, 0xfe, 0x00,
12879 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
12880 0x04, 0x07, 0x7e, 0xfe,
12881 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12882 0x07, 0x1a, 0xfe, 0x5a,
12883 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
12884 0x25, 0x6d, 0xe5, 0x07,
12885 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
12886 0xa9, 0xb8, 0x04, 0x15,
12887 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
12888 0x40, 0x5c, 0x04, 0x1c,
12889 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
12890 0xf7, 0xfe, 0x82, 0xf0,
12891 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012892};
12893
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012894static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
12895static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012896
12897/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012898static unsigned char _adv_asc38C1600_buf[] = {
12899 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
12900 0x18, 0xe4, 0x01, 0x00,
12901 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
12902 0x07, 0x17, 0xc0, 0x5f,
12903 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
12904 0x85, 0xf0, 0x86, 0xf0,
12905 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
12906 0x98, 0x57, 0x01, 0xe6,
12907 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
12908 0x38, 0x54, 0x32, 0xf0,
12909 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
12910 0x00, 0xe6, 0xb1, 0xf0,
12911 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
12912 0x06, 0x13, 0x0c, 0x1c,
12913 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
12914 0xb9, 0x54, 0x00, 0x80,
12915 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
12916 0x03, 0xe6, 0x01, 0xea,
12917 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
12918 0x04, 0x13, 0xbb, 0x55,
12919 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
12920 0xbb, 0x00, 0xc0, 0x00,
12921 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
12922 0x4c, 0x1c, 0x4e, 0x1c,
12923 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
12924 0x24, 0x01, 0x3c, 0x01,
12925 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
12926 0x78, 0x01, 0x7c, 0x01,
12927 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
12928 0x6e, 0x1e, 0x02, 0x48,
12929 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
12930 0x03, 0xfc, 0x06, 0x00,
12931 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
12932 0x30, 0x1c, 0x38, 0x1c,
12933 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
12934 0x5d, 0xf0, 0xa7, 0xf0,
12935 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
12936 0x33, 0x00, 0x34, 0x00,
12937 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
12938 0x79, 0x01, 0x3c, 0x09,
12939 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
12940 0x40, 0x16, 0x50, 0x16,
12941 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
12942 0x05, 0xf0, 0x09, 0xf0,
12943 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
12944 0x9c, 0x00, 0xa4, 0x00,
12945 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
12946 0xe9, 0x09, 0x5c, 0x0c,
12947 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
12948 0x42, 0x1d, 0x08, 0x44,
12949 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
12950 0x83, 0x55, 0x83, 0x59,
12951 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
12952 0x4b, 0xf4, 0x04, 0xf8,
12953 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
12954 0xa8, 0x00, 0xaa, 0x00,
12955 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
12956 0x7a, 0x01, 0x82, 0x01,
12957 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
12958 0x68, 0x08, 0x10, 0x0d,
12959 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
12960 0xf3, 0x10, 0x06, 0x12,
12961 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
12962 0xf0, 0x35, 0x05, 0xfe,
12963 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
12964 0xfe, 0x88, 0x01, 0xff,
12965 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12966 0x00, 0xfe, 0x57, 0x24,
12967 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
12968 0x00, 0x00, 0xff, 0x08,
12969 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12970 0xff, 0xff, 0xff, 0x13,
12971 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12972 0xfe, 0x04, 0xf7, 0xe8,
12973 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
12974 0x0d, 0x51, 0x37, 0xfe,
12975 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
12976 0xfe, 0xf8, 0x01, 0xfe,
12977 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
12978 0x05, 0xfe, 0x08, 0x0f,
12979 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
12980 0x28, 0x1c, 0x03, 0xfe,
12981 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
12982 0x48, 0xf0, 0xfe, 0x90,
12983 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
12984 0x02, 0xfe, 0x46, 0xf0,
12985 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
12986 0xfe, 0x4e, 0x02, 0xfe,
12987 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
12988 0x0d, 0xa2, 0x1c, 0x07,
12989 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
12990 0x1c, 0xf5, 0xfe, 0x1e,
12991 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
12992 0xde, 0x0a, 0x81, 0x01,
12993 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
12994 0x81, 0x01, 0x5c, 0xfe,
12995 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
12996 0xfe, 0x58, 0x1c, 0x1c,
12997 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
12998 0x2b, 0xfe, 0x9e, 0x02,
12999 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
13000 0x00, 0x47, 0xb8, 0x01,
13001 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
13002 0x1a, 0x31, 0xfe, 0x69,
13003 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
13004 0x1e, 0x1e, 0x20, 0x2c,
13005 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
13006 0x44, 0x15, 0x56, 0x51,
13007 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
13008 0x01, 0x18, 0x09, 0x00,
13009 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
13010 0x18, 0xfe, 0xc8, 0x54,
13011 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
13012 0xfe, 0x02, 0xe8, 0x30,
13013 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
13014 0xfe, 0xe4, 0x01, 0xfe,
13015 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
13016 0x26, 0xf0, 0xfe, 0x66,
13017 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
13018 0xef, 0x10, 0xfe, 0x9f,
13019 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
13020 0x70, 0x37, 0xfe, 0x48,
13021 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
13022 0x21, 0xb9, 0xc7, 0x20,
13023 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
13024 0xe1, 0x2a, 0xeb, 0xfe,
13025 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
13026 0x15, 0xfe, 0xe4, 0x00,
13027 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
13028 0xfe, 0x06, 0xf0, 0xfe,
13029 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
13030 0x03, 0x81, 0x1e, 0x1b,
13031 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
13032 0xea, 0xfe, 0x46, 0x1c,
13033 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
13034 0xfe, 0x48, 0x1c, 0x75,
13035 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
13036 0xe1, 0x01, 0x18, 0x77,
13037 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
13038 0x8f, 0xfe, 0x70, 0x02,
13039 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
13040 0x16, 0xfe, 0x4a, 0x04,
13041 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
13042 0x02, 0x00, 0x10, 0x01,
13043 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
13044 0xee, 0xfe, 0x4c, 0x44,
13045 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
13046 0x7b, 0xec, 0x60, 0x8d,
13047 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
13048 0x0c, 0x06, 0x28, 0xfe,
13049 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
13050 0x13, 0x34, 0xfe, 0x4c,
13051 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
13052 0x13, 0x01, 0x0c, 0x06,
13053 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
13054 0x28, 0xf9, 0x1f, 0x7f,
13055 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
13056 0xfe, 0xa4, 0x0e, 0x05,
13057 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
13058 0x9c, 0x93, 0x3a, 0x0b,
13059 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
13060 0x7d, 0x1d, 0xfe, 0x46,
13061 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
13062 0xfe, 0x87, 0x83, 0xfe,
13063 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
13064 0x13, 0x0f, 0xfe, 0x20,
13065 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
13066 0x12, 0x01, 0x38, 0x06,
13067 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
13068 0x05, 0xd0, 0x54, 0x01,
13069 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
13070 0x50, 0x12, 0x5e, 0xff,
13071 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
13072 0x00, 0x10, 0x2f, 0xfe,
13073 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
13074 0x38, 0xfe, 0x4a, 0xf0,
13075 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
13076 0x21, 0x00, 0xf1, 0x2e,
13077 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
13078 0x10, 0x2f, 0xfe, 0xd0,
13079 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
13080 0x1c, 0x00, 0x4d, 0x01,
13081 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
13082 0x28, 0xfe, 0x24, 0x12,
13083 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
13084 0x0d, 0x00, 0x01, 0x42,
13085 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
13086 0x03, 0xb6, 0x1e, 0xfe,
13087 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
13088 0xfe, 0x72, 0x06, 0x0a,
13089 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
13090 0x19, 0x16, 0xfe, 0x68,
13091 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
13092 0x03, 0x9a, 0x1e, 0xfe,
13093 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
13094 0x48, 0xfe, 0x92, 0x06,
13095 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
13096 0x58, 0xff, 0x02, 0x00,
13097 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
13098 0xfe, 0xea, 0x06, 0x01,
13099 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
13100 0xfe, 0xe0, 0x06, 0x15,
13101 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
13102 0x01, 0x84, 0xfe, 0xae,
13103 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
13104 0x1e, 0xfe, 0x1a, 0x12,
13105 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
13106 0x43, 0x48, 0x62, 0x80,
13107 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
13108 0x36, 0xfe, 0x02, 0xf6,
13109 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
13110 0xd0, 0x0d, 0x17, 0xfe,
13111 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
13112 0x9e, 0x15, 0x82, 0x01,
13113 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
13114 0x57, 0x10, 0xe6, 0x05,
13115 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
13116 0xfe, 0x9c, 0x32, 0x5f,
13117 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
13118 0xfe, 0x0a, 0xf0, 0xfe,
13119 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
13120 0xaf, 0xa0, 0x05, 0x29,
13121 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
13122 0x00, 0x01, 0x08, 0x14,
13123 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
13124 0x14, 0x00, 0x05, 0xfe,
13125 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
13126 0x12, 0xfe, 0x30, 0x13,
13127 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
13128 0x01, 0x08, 0x14, 0x00,
13129 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
13130 0x78, 0x4f, 0x0f, 0xfe,
13131 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
13132 0x28, 0x48, 0xfe, 0x6c,
13133 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
13134 0x12, 0x53, 0x63, 0x4e,
13135 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
13136 0x6c, 0x08, 0xaf, 0xa0,
13137 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
13138 0x05, 0xed, 0xfe, 0x9c,
13139 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
13140 0x1e, 0xfe, 0x99, 0x58,
13141 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
13142 0x22, 0x6b, 0x01, 0x0c,
13143 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
13144 0x1e, 0x47, 0x2c, 0x7a,
13145 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
13146 0x01, 0x0c, 0x61, 0x65,
13147 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
13148 0x16, 0xfe, 0x08, 0x50,
13149 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
13150 0x01, 0xfe, 0xce, 0x1e,
13151 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
13152 0x01, 0xfe, 0xfe, 0x1e,
13153 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
13154 0x10, 0x01, 0x0c, 0x06,
13155 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
13156 0x10, 0x6a, 0x22, 0x6b,
13157 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
13158 0xfe, 0x9f, 0x83, 0x33,
13159 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
13160 0x3a, 0x0b, 0xfe, 0xc6,
13161 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
13162 0x01, 0xfe, 0xce, 0x1e,
13163 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
13164 0x04, 0xfe, 0xc0, 0x93,
13165 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
13166 0x10, 0x4b, 0x22, 0x4c,
13167 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
13168 0x4e, 0x11, 0x2f, 0xfe,
13169 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
13170 0x3c, 0x37, 0x88, 0xf5,
13171 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
13172 0xd3, 0xfe, 0x42, 0x0a,
13173 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
13174 0x05, 0x29, 0x01, 0x41,
13175 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
13176 0xfe, 0x14, 0x12, 0x01,
13177 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
13178 0x2e, 0x1c, 0x05, 0xfe,
13179 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
13180 0xfe, 0x2c, 0x1c, 0xfe,
13181 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
13182 0x92, 0x10, 0xc4, 0xf6,
13183 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
13184 0xe7, 0x10, 0xfe, 0x2b,
13185 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
13186 0xac, 0xfe, 0xd2, 0xf0,
13187 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
13188 0x1b, 0xbf, 0xd4, 0x5b,
13189 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
13190 0x5e, 0x32, 0x1f, 0x7f,
13191 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
13192 0x05, 0x70, 0xfe, 0x74,
13193 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
13194 0x0f, 0x4d, 0x01, 0xfe,
13195 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
13196 0x0d, 0x2b, 0xfe, 0xe2,
13197 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
13198 0xfe, 0x88, 0x13, 0x21,
13199 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
13200 0x83, 0x83, 0xfe, 0xc9,
13201 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
13202 0x91, 0x04, 0xfe, 0x84,
13203 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
13204 0xfe, 0xcb, 0x57, 0x0b,
13205 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
13206 0x6a, 0x3b, 0x6b, 0x10,
13207 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
13208 0x20, 0x6e, 0xdb, 0x64,
13209 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
13210 0xfe, 0x04, 0xfa, 0x64,
13211 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
13212 0x10, 0x98, 0x91, 0x6c,
13213 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
13214 0x4b, 0x7e, 0x4c, 0x01,
13215 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
13216 0x58, 0xfe, 0x91, 0x58,
13217 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
13218 0x1b, 0x40, 0x01, 0x0c,
13219 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
13220 0xfe, 0x10, 0x90, 0x04,
13221 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
13222 0x79, 0x0b, 0x0e, 0xfe,
13223 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
13224 0x01, 0x0c, 0x06, 0x0d,
13225 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
13226 0x0c, 0x58, 0xfe, 0x8d,
13227 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
13228 0x83, 0x33, 0x0b, 0x0e,
13229 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
13230 0x19, 0xfe, 0x19, 0x41,
13231 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
13232 0x19, 0xfe, 0x44, 0x00,
13233 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
13234 0x4c, 0xfe, 0x0c, 0x51,
13235 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
13236 0x76, 0x10, 0xac, 0xfe,
13237 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
13238 0xe3, 0x23, 0x07, 0xfe,
13239 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
13240 0xcc, 0x0c, 0x1f, 0x92,
13241 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
13242 0x0c, 0xfe, 0x3e, 0x10,
13243 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
13244 0xfe, 0xcb, 0xf0, 0xfe,
13245 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
13246 0xf4, 0x0c, 0x19, 0x94,
13247 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
13248 0xfe, 0xcc, 0xf0, 0xef,
13249 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
13250 0x4e, 0x11, 0x2f, 0xfe,
13251 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
13252 0x3c, 0x37, 0x88, 0xf5,
13253 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
13254 0x2f, 0xfe, 0x3e, 0x0d,
13255 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
13256 0xd2, 0x9f, 0xd3, 0x9f,
13257 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
13258 0xc5, 0x75, 0xd7, 0x99,
13259 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
13260 0x9c, 0x2f, 0xfe, 0x8c,
13261 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
13262 0x42, 0x00, 0x05, 0x70,
13263 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
13264 0x0d, 0xfe, 0x44, 0x13,
13265 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
13266 0xfe, 0xda, 0x0e, 0x0a,
13267 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
13268 0x10, 0x01, 0xfe, 0xf4,
13269 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
13270 0x15, 0x56, 0x01, 0x85,
13271 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
13272 0xcc, 0x10, 0x01, 0xa7,
13273 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
13274 0xfe, 0x99, 0x83, 0xfe,
13275 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
13276 0x43, 0x00, 0xfe, 0xa2,
13277 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
13278 0x00, 0x1d, 0x40, 0x15,
13279 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
13280 0xfe, 0x3a, 0x03, 0x01,
13281 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
13282 0x76, 0x06, 0x12, 0xfe,
13283 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
13284 0xfe, 0x9d, 0xf0, 0xfe,
13285 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
13286 0x0c, 0x61, 0x12, 0x44,
13287 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
13288 0xfe, 0x2e, 0x10, 0x19,
13289 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
13290 0xfe, 0x41, 0x00, 0xa2,
13291 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
13292 0xea, 0x4f, 0xfe, 0x04,
13293 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
13294 0x35, 0xfe, 0x12, 0x1c,
13295 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
13296 0xfe, 0xd4, 0x11, 0x05,
13297 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
13298 0xce, 0x45, 0x31, 0x51,
13299 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
13300 0x67, 0xfe, 0x98, 0x56,
13301 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
13302 0x0c, 0x06, 0x28, 0xfe,
13303 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
13304 0xfe, 0xfa, 0x14, 0xfe,
13305 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
13306 0xfe, 0xe0, 0x14, 0xfe,
13307 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
13308 0xfe, 0xad, 0x13, 0x05,
13309 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
13310 0xe7, 0xfe, 0x08, 0x1c,
13311 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
13312 0x48, 0x55, 0xa5, 0x3b,
13313 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
13314 0xf0, 0x1a, 0x03, 0xfe,
13315 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
13316 0xec, 0xe7, 0x53, 0x00,
13317 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
13318 0x01, 0xfe, 0x62, 0x1b,
13319 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
13320 0xea, 0xe7, 0x53, 0x92,
13321 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
13322 0xfe, 0x38, 0x01, 0x23,
13323 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
13324 0x01, 0x01, 0xfe, 0x1e,
13325 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
13326 0x26, 0x02, 0x21, 0x96,
13327 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
13328 0xc3, 0xfe, 0xe1, 0x10,
13329 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
13330 0xfe, 0x03, 0xdc, 0xfe,
13331 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
13332 0x00, 0xcc, 0x02, 0xfe,
13333 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
13334 0x0f, 0xfe, 0x1c, 0x80,
13335 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
13336 0x0f, 0xfe, 0x1e, 0x80,
13337 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
13338 0x1d, 0x80, 0x04, 0xfe,
13339 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
13340 0x1e, 0xac, 0xfe, 0x14,
13341 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
13342 0x1f, 0xfe, 0x30, 0xf4,
13343 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
13344 0x56, 0xfb, 0x01, 0xfe,
13345 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
13346 0xfe, 0x00, 0x1d, 0x15,
13347 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
13348 0x22, 0x1b, 0xfe, 0x1e,
13349 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
13350 0x96, 0x90, 0x04, 0xfe,
13351 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
13352 0x01, 0x01, 0x0c, 0x06,
13353 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
13354 0x0e, 0x77, 0xfe, 0x01,
13355 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
13356 0x21, 0x2c, 0xfe, 0x00,
13357 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
13358 0x06, 0x58, 0x03, 0xfe,
13359 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
13360 0x03, 0xfe, 0xb2, 0x00,
13361 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
13362 0x66, 0x10, 0x55, 0x10,
13363 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
13364 0x54, 0x2b, 0xfe, 0x88,
13365 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
13366 0x91, 0x54, 0x2b, 0xfe,
13367 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
13368 0x00, 0x40, 0x8d, 0x2c,
13369 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
13370 0x12, 0x1c, 0x75, 0xfe,
13371 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
13372 0x14, 0xfe, 0x0e, 0x47,
13373 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
13374 0xa7, 0x90, 0x34, 0x60,
13375 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
13376 0x09, 0x56, 0xfe, 0x34,
13377 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
13378 0xfe, 0x45, 0x48, 0x01,
13379 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
13380 0x09, 0x1a, 0xa5, 0x0a,
13381 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
13382 0xfe, 0x14, 0x56, 0xfe,
13383 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
13384 0xec, 0xb8, 0xfe, 0x9e,
13385 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
13386 0xf4, 0xfe, 0xdd, 0x10,
13387 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
13388 0x12, 0x09, 0x0d, 0xfe,
13389 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
13390 0x13, 0x09, 0xfe, 0x23,
13391 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
13392 0x24, 0xfe, 0x12, 0x12,
13393 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
13394 0xae, 0x41, 0x02, 0x32,
13395 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
13396 0x35, 0x32, 0x01, 0x43,
13397 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
13398 0x13, 0x01, 0x0c, 0x06,
13399 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
13400 0xe5, 0x55, 0xb0, 0xfe,
13401 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
13402 0xfe, 0xb6, 0x0e, 0x10,
13403 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
13404 0x88, 0x20, 0x6e, 0x01,
13405 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
13406 0x55, 0xfe, 0x04, 0xfa,
13407 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
13408 0xfe, 0x40, 0x56, 0xfe,
13409 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
13410 0x44, 0x55, 0xfe, 0xe5,
13411 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
13412 0x68, 0x22, 0x69, 0x01,
13413 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
13414 0x6b, 0xfe, 0x2c, 0x50,
13415 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
13416 0x50, 0x03, 0x68, 0x3b,
13417 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
13418 0x40, 0x50, 0xfe, 0xc2,
13419 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
13420 0x16, 0x3d, 0x27, 0x25,
13421 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
13422 0xa6, 0x23, 0x3f, 0x1b,
13423 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
13424 0xfe, 0x0a, 0x55, 0x31,
13425 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
13426 0x51, 0x05, 0x72, 0x01,
13427 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
13428 0x2a, 0x3c, 0x16, 0xc0,
13429 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
13430 0xfe, 0x66, 0x15, 0x05,
13431 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
13432 0x2b, 0x3d, 0x01, 0x08,
13433 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
13434 0xb6, 0x1e, 0x83, 0x01,
13435 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
13436 0x07, 0x90, 0x3f, 0x01,
13437 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
13438 0x01, 0x43, 0x09, 0x82,
13439 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
13440 0x05, 0x72, 0xfe, 0xc0,
13441 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
13442 0x32, 0x01, 0x08, 0x17,
13443 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
13444 0x3d, 0x27, 0x25, 0xbd,
13445 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
13446 0xe8, 0x14, 0x01, 0xa6,
13447 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
13448 0x0e, 0x12, 0x01, 0x43,
13449 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
13450 0x01, 0x08, 0x17, 0x73,
13451 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
13452 0x27, 0x25, 0xbd, 0x09,
13453 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
13454 0xb6, 0x14, 0x86, 0xa8,
13455 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
13456 0x82, 0x4e, 0x05, 0x72,
13457 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
13458 0xfe, 0xc0, 0x19, 0x05,
13459 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
13460 0xcc, 0x01, 0x08, 0x26,
13461 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
13462 0xcc, 0x15, 0x5e, 0x32,
13463 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
13464 0xad, 0x23, 0xfe, 0xff,
13465 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
13466 0x00, 0x57, 0x52, 0xad,
13467 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
13468 0x02, 0x00, 0x57, 0x52,
13469 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
13470 0x02, 0x13, 0x58, 0xff,
13471 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
13472 0x5c, 0x0a, 0x55, 0x01,
13473 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
13474 0xff, 0x03, 0x00, 0x54,
13475 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
13476 0x7c, 0x3a, 0x0b, 0x0e,
13477 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
13478 0xfe, 0x1a, 0xf7, 0x00,
13479 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
13480 0xda, 0x6d, 0x02, 0xfe,
13481 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
13482 0x02, 0x01, 0xc6, 0xfe,
13483 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
13484 0x25, 0xbe, 0x01, 0x08,
13485 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
13486 0x03, 0x9a, 0x1e, 0xfe,
13487 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
13488 0x48, 0xfe, 0x08, 0x17,
13489 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
13490 0x17, 0x4d, 0x13, 0x07,
13491 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
13492 0xff, 0x02, 0x83, 0x55,
13493 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
13494 0x17, 0x1c, 0x63, 0x13,
13495 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
13496 0x00, 0xb0, 0xfe, 0x80,
13497 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
13498 0x53, 0x07, 0xfe, 0x60,
13499 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
13500 0x00, 0x1c, 0x95, 0x13,
13501 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
13502 0xfe, 0x43, 0xf4, 0x96,
13503 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
13504 0xf4, 0x94, 0xf6, 0x8b,
13505 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
13506 0xda, 0x17, 0x62, 0x49,
13507 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
13508 0x71, 0x50, 0x26, 0xfe,
13509 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
13510 0x58, 0x02, 0x50, 0x13,
13511 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
13512 0x25, 0xbe, 0xfe, 0x03,
13513 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
13514 0x0a, 0x01, 0x08, 0x16,
13515 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13516 0x01, 0x08, 0x16, 0xa9,
13517 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13518 0x08, 0x16, 0xa9, 0x27,
13519 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13520 0x01, 0x38, 0x06, 0x24,
13521 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13522 0x78, 0x03, 0x9a, 0x1e,
13523 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13524 0xfe, 0x40, 0x5a, 0x23,
13525 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13526 0x80, 0x48, 0xfe, 0xaa,
13527 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13528 0xfe, 0xac, 0x1d, 0xfe,
13529 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13530 0x43, 0x48, 0x2d, 0x93,
13531 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13532 0x36, 0xfe, 0x34, 0xf4,
13533 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13534 0x28, 0x10, 0xfe, 0xc0,
13535 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13536 0x18, 0x45, 0xfe, 0x1c,
13537 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13538 0x19, 0xfe, 0x04, 0xf4,
13539 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13540 0x21, 0xfe, 0x7f, 0x01,
13541 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13542 0x7e, 0x01, 0xfe, 0xc8,
13543 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13544 0x21, 0xfe, 0x81, 0x01,
13545 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13546 0x13, 0x0d, 0x02, 0x14,
13547 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13548 0xfe, 0x82, 0x19, 0x14,
13549 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13550 0x08, 0x02, 0x14, 0x07,
13551 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13552 0x01, 0x08, 0x17, 0xc1,
13553 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13554 0x08, 0x02, 0x50, 0x02,
13555 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13556 0x14, 0x12, 0x01, 0x08,
13557 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13558 0x08, 0x17, 0x74, 0xfe,
13559 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13560 0x74, 0x5f, 0xcc, 0x01,
13561 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13562 0xfe, 0x49, 0xf4, 0x00,
13563 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13564 0x02, 0x00, 0x10, 0x2f,
13565 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13566 0x16, 0xfe, 0x64, 0x1a,
13567 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13568 0x61, 0x07, 0x44, 0x02,
13569 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13570 0x13, 0x0a, 0x9d, 0x01,
13571 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13572 0xfe, 0x80, 0xe7, 0x1a,
13573 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13574 0x0a, 0x5a, 0x01, 0x18,
13575 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13576 0x7e, 0x1e, 0xfe, 0x80,
13577 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13578 0xfe, 0x80, 0x4c, 0x0a,
13579 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13580 0xfe, 0x19, 0xde, 0xfe,
13581 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13582 0x2a, 0x1c, 0xfa, 0xb3,
13583 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13584 0xf4, 0x1a, 0xfe, 0xfa,
13585 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13586 0xfe, 0x18, 0x58, 0x03,
13587 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13588 0xfe, 0x30, 0xf4, 0x07,
13589 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13590 0xf7, 0x24, 0xb1, 0xfe,
13591 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13592 0xfe, 0xba, 0x10, 0x1c,
13593 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13594 0x1d, 0xf7, 0x54, 0xb1,
13595 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13596 0xaf, 0x19, 0xfe, 0x98,
13597 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13598 0x1a, 0x87, 0x8b, 0x0f,
13599 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13600 0xfe, 0x32, 0x90, 0x04,
13601 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13602 0x7c, 0x12, 0xfe, 0x0f,
13603 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13604 0x31, 0x02, 0xc9, 0x2b,
13605 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13606 0x6a, 0xfe, 0x19, 0xfe,
13607 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13608 0x1b, 0xfe, 0x36, 0x14,
13609 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13610 0xfe, 0x80, 0xe7, 0x1a,
13611 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13612 0x30, 0xfe, 0x12, 0x45,
13613 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13614 0x39, 0xf0, 0x75, 0x26,
13615 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13616 0xe3, 0x23, 0x07, 0xfe,
13617 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13618 0x56, 0xfe, 0x3c, 0x13,
13619 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13620 0x01, 0x18, 0xcb, 0xfe,
13621 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13622 0xfe, 0x00, 0xcc, 0xcb,
13623 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13624 0xfe, 0x80, 0x4c, 0x01,
13625 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13626 0x12, 0xfe, 0x14, 0x56,
13627 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13628 0x0d, 0x19, 0xfe, 0x15,
13629 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13630 0x83, 0xfe, 0x18, 0x80,
13631 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13632 0x90, 0xfe, 0xba, 0x90,
13633 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13634 0x21, 0xb9, 0x88, 0x20,
13635 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13636 0x18, 0xfe, 0x49, 0x44,
13637 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13638 0x1a, 0xa4, 0x0a, 0x67,
13639 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13640 0x1d, 0x7b, 0xfe, 0x52,
13641 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13642 0x4e, 0xe4, 0xdd, 0x7b,
13643 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13644 0xfe, 0x4e, 0xe4, 0xfe,
13645 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13646 0xfe, 0x08, 0x10, 0x03,
13647 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13648 0x68, 0x54, 0xfe, 0xf1,
13649 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13650 0xfe, 0x1a, 0xf4, 0xfe,
13651 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13652 0x09, 0x92, 0xfe, 0x5a,
13653 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13654 0x5a, 0xf0, 0xfe, 0xc8,
13655 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13656 0x1a, 0x10, 0x09, 0x0d,
13657 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13658 0x1f, 0x93, 0x01, 0x42,
13659 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13660 0xfe, 0x14, 0xf0, 0x08,
13661 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13662 0xfe, 0x82, 0xf0, 0xfe,
13663 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13664 0x02, 0x0f, 0xfe, 0x18,
13665 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13666 0x80, 0x04, 0xfe, 0x82,
13667 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13668 0x83, 0x33, 0x0b, 0x0e,
13669 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13670 0x02, 0x0f, 0xfe, 0x04,
13671 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13672 0x80, 0x04, 0xfe, 0x80,
13673 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13674 0xfe, 0x99, 0x83, 0xfe,
13675 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13676 0x83, 0xfe, 0xce, 0x47,
13677 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13678 0x0b, 0x0e, 0x02, 0x0f,
13679 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13680 0xfe, 0x08, 0x90, 0x04,
13681 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13682 0xfe, 0x8a, 0x93, 0x79,
13683 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13684 0x0b, 0x0e, 0x02, 0x0f,
13685 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13686 0xfe, 0x3c, 0x90, 0x04,
13687 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13688 0x04, 0xfe, 0x83, 0x83,
13689 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013690};
13691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013692static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13693static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013694
13695/* a_init.c */
13696/*
13697 * EEPROM Configuration.
13698 *
13699 * All drivers should use this structure to set the default EEPROM
13700 * configuration. The BIOS now uses this structure when it is built.
13701 * Additional structure information can be found in a_condor.h where
13702 * the structure is defined.
13703 *
13704 * The *_Field_IsChar structs are needed to correct for endianness.
13705 * These values are read from the board 16 bits at a time directly
13706 * into the structs. Because some fields are char, the values will be
13707 * in the wrong order. The *_Field_IsChar tells when to flip the
13708 * bytes. Data read and written to PCI memory is automatically swapped
13709 * on big-endian platforms so char fields read as words are actually being
13710 * unswapped on big-endian platforms.
13711 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013712static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013713 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13714 0x0000, /* cfg_msw */
13715 0xFFFF, /* disc_enable */
13716 0xFFFF, /* wdtr_able */
13717 0xFFFF, /* sdtr_able */
13718 0xFFFF, /* start_motor */
13719 0xFFFF, /* tagqng_able */
13720 0xFFFF, /* bios_scan */
13721 0, /* scam_tolerant */
13722 7, /* adapter_scsi_id */
13723 0, /* bios_boot_delay */
13724 3, /* scsi_reset_delay */
13725 0, /* bios_id_lun */
13726 0, /* termination */
13727 0, /* reserved1 */
13728 0xFFE7, /* bios_ctrl */
13729 0xFFFF, /* ultra_able */
13730 0, /* reserved2 */
13731 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13732 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13733 0, /* dvc_cntl */
13734 0, /* bug_fix */
13735 0, /* serial_number_word1 */
13736 0, /* serial_number_word2 */
13737 0, /* serial_number_word3 */
13738 0, /* check_sum */
13739 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13740 , /* oem_name[16] */
13741 0, /* dvc_err_code */
13742 0, /* adv_err_code */
13743 0, /* adv_err_addr */
13744 0, /* saved_dvc_err_code */
13745 0, /* saved_adv_err_code */
13746 0, /* saved_adv_err_addr */
13747 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013748};
13749
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013750static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013751 0, /* cfg_lsw */
13752 0, /* cfg_msw */
13753 0, /* -disc_enable */
13754 0, /* wdtr_able */
13755 0, /* sdtr_able */
13756 0, /* start_motor */
13757 0, /* tagqng_able */
13758 0, /* bios_scan */
13759 0, /* scam_tolerant */
13760 1, /* adapter_scsi_id */
13761 1, /* bios_boot_delay */
13762 1, /* scsi_reset_delay */
13763 1, /* bios_id_lun */
13764 1, /* termination */
13765 1, /* reserved1 */
13766 0, /* bios_ctrl */
13767 0, /* ultra_able */
13768 0, /* reserved2 */
13769 1, /* max_host_qng */
13770 1, /* max_dvc_qng */
13771 0, /* dvc_cntl */
13772 0, /* bug_fix */
13773 0, /* serial_number_word1 */
13774 0, /* serial_number_word2 */
13775 0, /* serial_number_word3 */
13776 0, /* check_sum */
13777 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13778 , /* oem_name[16] */
13779 0, /* dvc_err_code */
13780 0, /* adv_err_code */
13781 0, /* adv_err_addr */
13782 0, /* saved_dvc_err_code */
13783 0, /* saved_adv_err_code */
13784 0, /* saved_adv_err_addr */
13785 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013786};
13787
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013788static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013789 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13790 0x0000, /* 01 cfg_msw */
13791 0xFFFF, /* 02 disc_enable */
13792 0xFFFF, /* 03 wdtr_able */
13793 0x4444, /* 04 sdtr_speed1 */
13794 0xFFFF, /* 05 start_motor */
13795 0xFFFF, /* 06 tagqng_able */
13796 0xFFFF, /* 07 bios_scan */
13797 0, /* 08 scam_tolerant */
13798 7, /* 09 adapter_scsi_id */
13799 0, /* bios_boot_delay */
13800 3, /* 10 scsi_reset_delay */
13801 0, /* bios_id_lun */
13802 0, /* 11 termination_se */
13803 0, /* termination_lvd */
13804 0xFFE7, /* 12 bios_ctrl */
13805 0x4444, /* 13 sdtr_speed2 */
13806 0x4444, /* 14 sdtr_speed3 */
13807 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13808 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13809 0, /* 16 dvc_cntl */
13810 0x4444, /* 17 sdtr_speed4 */
13811 0, /* 18 serial_number_word1 */
13812 0, /* 19 serial_number_word2 */
13813 0, /* 20 serial_number_word3 */
13814 0, /* 21 check_sum */
13815 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13816 , /* 22-29 oem_name[16] */
13817 0, /* 30 dvc_err_code */
13818 0, /* 31 adv_err_code */
13819 0, /* 32 adv_err_addr */
13820 0, /* 33 saved_dvc_err_code */
13821 0, /* 34 saved_adv_err_code */
13822 0, /* 35 saved_adv_err_addr */
13823 0, /* 36 reserved */
13824 0, /* 37 reserved */
13825 0, /* 38 reserved */
13826 0, /* 39 reserved */
13827 0, /* 40 reserved */
13828 0, /* 41 reserved */
13829 0, /* 42 reserved */
13830 0, /* 43 reserved */
13831 0, /* 44 reserved */
13832 0, /* 45 reserved */
13833 0, /* 46 reserved */
13834 0, /* 47 reserved */
13835 0, /* 48 reserved */
13836 0, /* 49 reserved */
13837 0, /* 50 reserved */
13838 0, /* 51 reserved */
13839 0, /* 52 reserved */
13840 0, /* 53 reserved */
13841 0, /* 54 reserved */
13842 0, /* 55 reserved */
13843 0, /* 56 cisptr_lsw */
13844 0, /* 57 cisprt_msw */
13845 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13846 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13847 0, /* 60 reserved */
13848 0, /* 61 reserved */
13849 0, /* 62 reserved */
13850 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013851};
13852
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013853static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013854 0, /* 00 cfg_lsw */
13855 0, /* 01 cfg_msw */
13856 0, /* 02 disc_enable */
13857 0, /* 03 wdtr_able */
13858 0, /* 04 sdtr_speed1 */
13859 0, /* 05 start_motor */
13860 0, /* 06 tagqng_able */
13861 0, /* 07 bios_scan */
13862 0, /* 08 scam_tolerant */
13863 1, /* 09 adapter_scsi_id */
13864 1, /* bios_boot_delay */
13865 1, /* 10 scsi_reset_delay */
13866 1, /* bios_id_lun */
13867 1, /* 11 termination_se */
13868 1, /* termination_lvd */
13869 0, /* 12 bios_ctrl */
13870 0, /* 13 sdtr_speed2 */
13871 0, /* 14 sdtr_speed3 */
13872 1, /* 15 max_host_qng */
13873 1, /* max_dvc_qng */
13874 0, /* 16 dvc_cntl */
13875 0, /* 17 sdtr_speed4 */
13876 0, /* 18 serial_number_word1 */
13877 0, /* 19 serial_number_word2 */
13878 0, /* 20 serial_number_word3 */
13879 0, /* 21 check_sum */
13880 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13881 , /* 22-29 oem_name[16] */
13882 0, /* 30 dvc_err_code */
13883 0, /* 31 adv_err_code */
13884 0, /* 32 adv_err_addr */
13885 0, /* 33 saved_dvc_err_code */
13886 0, /* 34 saved_adv_err_code */
13887 0, /* 35 saved_adv_err_addr */
13888 0, /* 36 reserved */
13889 0, /* 37 reserved */
13890 0, /* 38 reserved */
13891 0, /* 39 reserved */
13892 0, /* 40 reserved */
13893 0, /* 41 reserved */
13894 0, /* 42 reserved */
13895 0, /* 43 reserved */
13896 0, /* 44 reserved */
13897 0, /* 45 reserved */
13898 0, /* 46 reserved */
13899 0, /* 47 reserved */
13900 0, /* 48 reserved */
13901 0, /* 49 reserved */
13902 0, /* 50 reserved */
13903 0, /* 51 reserved */
13904 0, /* 52 reserved */
13905 0, /* 53 reserved */
13906 0, /* 54 reserved */
13907 0, /* 55 reserved */
13908 0, /* 56 cisptr_lsw */
13909 0, /* 57 cisprt_msw */
13910 0, /* 58 subsysvid */
13911 0, /* 59 subsysid */
13912 0, /* 60 reserved */
13913 0, /* 61 reserved */
13914 0, /* 62 reserved */
13915 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013916};
13917
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013918static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013919 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13920 0x0000, /* 01 cfg_msw */
13921 0xFFFF, /* 02 disc_enable */
13922 0xFFFF, /* 03 wdtr_able */
13923 0x5555, /* 04 sdtr_speed1 */
13924 0xFFFF, /* 05 start_motor */
13925 0xFFFF, /* 06 tagqng_able */
13926 0xFFFF, /* 07 bios_scan */
13927 0, /* 08 scam_tolerant */
13928 7, /* 09 adapter_scsi_id */
13929 0, /* bios_boot_delay */
13930 3, /* 10 scsi_reset_delay */
13931 0, /* bios_id_lun */
13932 0, /* 11 termination_se */
13933 0, /* termination_lvd */
13934 0xFFE7, /* 12 bios_ctrl */
13935 0x5555, /* 13 sdtr_speed2 */
13936 0x5555, /* 14 sdtr_speed3 */
13937 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13938 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13939 0, /* 16 dvc_cntl */
13940 0x5555, /* 17 sdtr_speed4 */
13941 0, /* 18 serial_number_word1 */
13942 0, /* 19 serial_number_word2 */
13943 0, /* 20 serial_number_word3 */
13944 0, /* 21 check_sum */
13945 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13946 , /* 22-29 oem_name[16] */
13947 0, /* 30 dvc_err_code */
13948 0, /* 31 adv_err_code */
13949 0, /* 32 adv_err_addr */
13950 0, /* 33 saved_dvc_err_code */
13951 0, /* 34 saved_adv_err_code */
13952 0, /* 35 saved_adv_err_addr */
13953 0, /* 36 reserved */
13954 0, /* 37 reserved */
13955 0, /* 38 reserved */
13956 0, /* 39 reserved */
13957 0, /* 40 reserved */
13958 0, /* 41 reserved */
13959 0, /* 42 reserved */
13960 0, /* 43 reserved */
13961 0, /* 44 reserved */
13962 0, /* 45 reserved */
13963 0, /* 46 reserved */
13964 0, /* 47 reserved */
13965 0, /* 48 reserved */
13966 0, /* 49 reserved */
13967 0, /* 50 reserved */
13968 0, /* 51 reserved */
13969 0, /* 52 reserved */
13970 0, /* 53 reserved */
13971 0, /* 54 reserved */
13972 0, /* 55 reserved */
13973 0, /* 56 cisptr_lsw */
13974 0, /* 57 cisprt_msw */
13975 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13976 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
13977 0, /* 60 reserved */
13978 0, /* 61 reserved */
13979 0, /* 62 reserved */
13980 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013981};
13982
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013983static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013984 0, /* 00 cfg_lsw */
13985 0, /* 01 cfg_msw */
13986 0, /* 02 disc_enable */
13987 0, /* 03 wdtr_able */
13988 0, /* 04 sdtr_speed1 */
13989 0, /* 05 start_motor */
13990 0, /* 06 tagqng_able */
13991 0, /* 07 bios_scan */
13992 0, /* 08 scam_tolerant */
13993 1, /* 09 adapter_scsi_id */
13994 1, /* bios_boot_delay */
13995 1, /* 10 scsi_reset_delay */
13996 1, /* bios_id_lun */
13997 1, /* 11 termination_se */
13998 1, /* termination_lvd */
13999 0, /* 12 bios_ctrl */
14000 0, /* 13 sdtr_speed2 */
14001 0, /* 14 sdtr_speed3 */
14002 1, /* 15 max_host_qng */
14003 1, /* max_dvc_qng */
14004 0, /* 16 dvc_cntl */
14005 0, /* 17 sdtr_speed4 */
14006 0, /* 18 serial_number_word1 */
14007 0, /* 19 serial_number_word2 */
14008 0, /* 20 serial_number_word3 */
14009 0, /* 21 check_sum */
14010 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
14011 , /* 22-29 oem_name[16] */
14012 0, /* 30 dvc_err_code */
14013 0, /* 31 adv_err_code */
14014 0, /* 32 adv_err_addr */
14015 0, /* 33 saved_dvc_err_code */
14016 0, /* 34 saved_adv_err_code */
14017 0, /* 35 saved_adv_err_addr */
14018 0, /* 36 reserved */
14019 0, /* 37 reserved */
14020 0, /* 38 reserved */
14021 0, /* 39 reserved */
14022 0, /* 40 reserved */
14023 0, /* 41 reserved */
14024 0, /* 42 reserved */
14025 0, /* 43 reserved */
14026 0, /* 44 reserved */
14027 0, /* 45 reserved */
14028 0, /* 46 reserved */
14029 0, /* 47 reserved */
14030 0, /* 48 reserved */
14031 0, /* 49 reserved */
14032 0, /* 50 reserved */
14033 0, /* 51 reserved */
14034 0, /* 52 reserved */
14035 0, /* 53 reserved */
14036 0, /* 54 reserved */
14037 0, /* 55 reserved */
14038 0, /* 56 cisptr_lsw */
14039 0, /* 57 cisprt_msw */
14040 0, /* 58 subsysvid */
14041 0, /* 59 subsysid */
14042 0, /* 60 reserved */
14043 0, /* 61 reserved */
14044 0, /* 62 reserved */
14045 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014046};
14047
14048/*
14049 * Initialize the ADV_DVC_VAR structure.
14050 *
14051 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14052 *
14053 * For a non-fatal error return a warning code. If there are no warnings
14054 * then 0 is returned.
14055 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060014056static int __devinit AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014057{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014058 ushort warn_code;
14059 AdvPortAddr iop_base;
14060 uchar pci_cmd_reg;
14061 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014062
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014063 warn_code = 0;
14064 asc_dvc->err_code = 0;
14065 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014066
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014067 /*
14068 * PCI Command Register
14069 *
14070 * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
14071 * I/O Space Control, Memory Space Control and Bus Master Control bits.
14072 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014073
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014074 if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
14075 AscPCIConfigCommandRegister))
14076 & AscPCICmdRegBits_BusMastering)
14077 != AscPCICmdRegBits_BusMastering) {
14078 pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014079
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014080 DvcAdvWritePCIConfigByte(asc_dvc,
14081 AscPCIConfigCommandRegister,
14082 pci_cmd_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014083
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014084 if (((DvcAdvReadPCIConfigByte
14085 (asc_dvc, AscPCIConfigCommandRegister))
14086 & AscPCICmdRegBits_BusMastering)
14087 != AscPCICmdRegBits_BusMastering) {
14088 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
14089 }
14090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014091
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014092 /*
14093 * PCI Latency Timer
14094 *
14095 * If the "latency timer" register is 0x20 or above, then we don't need
14096 * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
14097 * comes up less than 0x20).
14098 */
14099 if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
14100 DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer,
14101 0x20);
14102 if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) <
14103 0x20) {
14104 warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
14105 }
14106 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014107
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014108 /*
14109 * Save the state of the PCI Configuration Command Register
14110 * "Parity Error Response Control" Bit. If the bit is clear (0),
14111 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
14112 * DMA parity errors.
14113 */
14114 asc_dvc->cfg->control_flag = 0;
14115 if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
14116 & AscPCICmdRegBits_ParErrRespCtrl)) == 0) {
14117 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
14118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014119
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014120 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
14121 ADV_LIB_VERSION_MINOR;
14122 asc_dvc->cfg->chip_version =
14123 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014124
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014125 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
14126 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
14127 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014128
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014129 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
14130 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
14131 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014132
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014133 /*
14134 * Reset the chip to start and allow register writes.
14135 */
14136 if (AdvFindSignature(iop_base) == 0) {
14137 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
14138 return ADV_ERROR;
14139 } else {
14140 /*
14141 * The caller must set 'chip_type' to a valid setting.
14142 */
14143 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
14144 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
14145 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
14146 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
14147 return ADV_ERROR;
14148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014149
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014150 /*
14151 * Reset Chip.
14152 */
14153 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
14154 ADV_CTRL_REG_CMD_RESET);
14155 DvcSleepMilliSecond(100);
14156 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
14157 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014158
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014159 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
14160 if ((status =
14161 AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) {
14162 return ADV_ERROR;
14163 }
14164 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
14165 if ((status =
14166 AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) {
14167 return ADV_ERROR;
14168 }
14169 } else {
14170 if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR) {
14171 return ADV_ERROR;
14172 }
14173 }
14174 warn_code |= status;
14175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014176
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014177 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014178}
14179
14180/*
14181 * Initialize the ASC-3550.
14182 *
14183 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14184 *
14185 * For a non-fatal error return a warning code. If there are no warnings
14186 * then 0 is returned.
14187 *
14188 * Needed after initialization for error recovery.
14189 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014190static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014191{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014192 AdvPortAddr iop_base;
14193 ushort warn_code;
14194 ADV_DCNT sum;
14195 int begin_addr;
14196 int end_addr;
14197 ushort code_sum;
14198 int word;
14199 int j;
14200 int adv_asc3550_expanded_size;
14201 ADV_CARR_T *carrp;
14202 ADV_DCNT contig_len;
14203 ADV_SDCNT buf_size;
14204 ADV_PADDR carr_paddr;
14205 int i;
14206 ushort scsi_cfg1;
14207 uchar tid;
14208 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14209 ushort wdtr_able = 0, sdtr_able, tagqng_able;
14210 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014212 /* If there is already an error, don't continue. */
14213 if (asc_dvc->err_code != 0) {
14214 return ADV_ERROR;
14215 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014216
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014217 /*
14218 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
14219 */
14220 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
14221 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
14222 return ADV_ERROR;
14223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014224
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014225 warn_code = 0;
14226 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014227
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014228 /*
14229 * Save the RISC memory BIOS region before writing the microcode.
14230 * The BIOS may already be loaded and using its RISC LRAM region
14231 * so its region must be saved and restored.
14232 *
14233 * Note: This code makes the assumption, which is currently true,
14234 * that a chip reset does not clear RISC LRAM.
14235 */
14236 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14237 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14238 bios_mem[i]);
14239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014240
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014241 /*
14242 * Save current per TID negotiated values.
14243 */
14244 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
14245 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014246
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014247 bios_version =
14248 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
14249 major = (bios_version >> 12) & 0xF;
14250 minor = (bios_version >> 8) & 0xF;
14251 if (major < 3 || (major == 3 && minor == 1)) {
14252 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
14253 AdvReadWordLram(iop_base, 0x120, wdtr_able);
14254 } else {
14255 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14256 }
14257 }
14258 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14259 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14260 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14261 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14262 max_cmd[tid]);
14263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014264
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014265 /*
14266 * Load the Microcode
14267 *
14268 * Write the microcode image to RISC memory starting at address 0.
14269 */
14270 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
14271 /* Assume the following compressed format of the microcode buffer:
14272 *
14273 * 254 word (508 byte) table indexed by byte code followed
14274 * by the following byte codes:
14275 *
14276 * 1-Byte Code:
14277 * 00: Emit word 0 in table.
14278 * 01: Emit word 1 in table.
14279 * .
14280 * FD: Emit word 253 in table.
14281 *
14282 * Multi-Byte Code:
14283 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14284 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14285 */
14286 word = 0;
14287 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
14288 if (_adv_asc3550_buf[i] == 0xff) {
14289 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
14290 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14291 _adv_asc3550_buf
14292 [i +
14293 3] << 8) |
14294 _adv_asc3550_buf
14295 [i + 2]));
14296 word++;
14297 }
14298 i += 3;
14299 } else if (_adv_asc3550_buf[i] == 0xfe) {
14300 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14301 _adv_asc3550_buf[i +
14302 2]
14303 << 8) |
14304 _adv_asc3550_buf[i +
14305 1]));
14306 i += 2;
14307 word++;
14308 } else {
14309 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14310 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
14311 word++;
14312 }
14313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014314
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014315 /*
14316 * Set 'word' for later use to clear the rest of memory and save
14317 * the expanded mcode size.
14318 */
14319 word *= 2;
14320 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014321
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014322 /*
14323 * Clear the rest of ASC-3550 Internal RAM (8KB).
14324 */
14325 for (; word < ADV_3550_MEMSIZE; word += 2) {
14326 AdvWriteWordAutoIncLram(iop_base, 0);
14327 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014328
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014329 /*
14330 * Verify the microcode checksum.
14331 */
14332 sum = 0;
14333 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014334
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014335 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
14336 sum += AdvReadWordAutoIncLram(iop_base);
14337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014338
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014339 if (sum != _adv_asc3550_chksum) {
14340 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14341 return ADV_ERROR;
14342 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014343
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014344 /*
14345 * Restore the RISC memory BIOS region.
14346 */
14347 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14348 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14349 bios_mem[i]);
14350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014351
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014352 /*
14353 * Calculate and write the microcode code checksum to the microcode
14354 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14355 */
14356 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14357 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14358 code_sum = 0;
14359 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14360 for (word = begin_addr; word < end_addr; word += 2) {
14361 code_sum += AdvReadWordAutoIncLram(iop_base);
14362 }
14363 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014364
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014365 /*
14366 * Read and save microcode version and date.
14367 */
14368 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14369 asc_dvc->cfg->mcode_date);
14370 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14371 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014372
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014373 /*
14374 * Set the chip type to indicate the ASC3550.
14375 */
14376 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014377
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014378 /*
14379 * If the PCI Configuration Command Register "Parity Error Response
14380 * Control" Bit was clear (0), then set the microcode variable
14381 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14382 * to ignore DMA parity errors.
14383 */
14384 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14385 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14386 word |= CONTROL_FLAG_IGNORE_PERR;
14387 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014389
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014390 /*
14391 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
14392 * threshold of 128 bytes. This register is only accessible to the host.
14393 */
14394 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14395 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014396
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014397 /*
14398 * Microcode operating variables for WDTR, SDTR, and command tag
14399 * queuing will be set in AdvInquiryHandling() based on what a
14400 * device reports it is capable of in Inquiry byte 7.
14401 *
14402 * If SCSI Bus Resets have been disabled, then directly set
14403 * SDTR and WDTR from the EEPROM configuration. This will allow
14404 * the BIOS and warm boot to work without a SCSI bus hang on
14405 * the Inquiry caused by host and target mismatched DTR values.
14406 * Without the SCSI Bus Reset, before an Inquiry a device can't
14407 * be assumed to be in Asynchronous, Narrow mode.
14408 */
14409 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14410 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14411 asc_dvc->wdtr_able);
14412 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14413 asc_dvc->sdtr_able);
14414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014415
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014416 /*
14417 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
14418 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
14419 * bitmask. These values determine the maximum SDTR speed negotiated
14420 * with a device.
14421 *
14422 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14423 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14424 * without determining here whether the device supports SDTR.
14425 *
14426 * 4-bit speed SDTR speed name
14427 * =========== ===============
14428 * 0000b (0x0) SDTR disabled
14429 * 0001b (0x1) 5 Mhz
14430 * 0010b (0x2) 10 Mhz
14431 * 0011b (0x3) 20 Mhz (Ultra)
14432 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
14433 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
14434 * 0110b (0x6) Undefined
14435 * .
14436 * 1111b (0xF) Undefined
14437 */
14438 word = 0;
14439 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14440 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
14441 /* Set Ultra speed for TID 'tid'. */
14442 word |= (0x3 << (4 * (tid % 4)));
14443 } else {
14444 /* Set Fast speed for TID 'tid'. */
14445 word |= (0x2 << (4 * (tid % 4)));
14446 }
14447 if (tid == 3) { /* Check if done with sdtr_speed1. */
14448 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
14449 word = 0;
14450 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
14451 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
14452 word = 0;
14453 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
14454 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
14455 word = 0;
14456 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
14457 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
14458 /* End of loop. */
14459 }
14460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014461
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014462 /*
14463 * Set microcode operating variable for the disconnect per TID bitmask.
14464 */
14465 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14466 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014467
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014468 /*
14469 * Set SCSI_CFG0 Microcode Default Value.
14470 *
14471 * The microcode will set the SCSI_CFG0 register using this value
14472 * after it is started below.
14473 */
14474 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14475 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14476 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014477
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014478 /*
14479 * Determine SCSI_CFG1 Microcode Default Value.
14480 *
14481 * The microcode will set the SCSI_CFG1 register using this value
14482 * after it is started below.
14483 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014484
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014485 /* Read current SCSI_CFG1 Register value. */
14486 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014487
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014488 /*
14489 * If all three connectors are in use, return an error.
14490 */
14491 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
14492 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
14493 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
14494 return ADV_ERROR;
14495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014496
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014497 /*
14498 * If the internal narrow cable is reversed all of the SCSI_CTRL
14499 * register signals will be set. Check for and return an error if
14500 * this condition is found.
14501 */
14502 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14503 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14504 return ADV_ERROR;
14505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014506
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014507 /*
14508 * If this is a differential board and a single-ended device
14509 * is attached to one of the connectors, return an error.
14510 */
14511 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
14512 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
14513 return ADV_ERROR;
14514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014515
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014516 /*
14517 * If automatic termination control is enabled, then set the
14518 * termination value based on a table listed in a_condor.h.
14519 *
14520 * If manual termination was specified with an EEPROM setting
14521 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
14522 * is ready to be 'ored' into SCSI_CFG1.
14523 */
14524 if (asc_dvc->cfg->termination == 0) {
14525 /*
14526 * The software always controls termination by setting TERM_CTL_SEL.
14527 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
14528 */
14529 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014530
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014531 switch (scsi_cfg1 & CABLE_DETECT) {
14532 /* TERM_CTL_H: on, TERM_CTL_L: on */
14533 case 0x3:
14534 case 0x7:
14535 case 0xB:
14536 case 0xD:
14537 case 0xE:
14538 case 0xF:
14539 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
14540 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014541
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014542 /* TERM_CTL_H: on, TERM_CTL_L: off */
14543 case 0x1:
14544 case 0x5:
14545 case 0x9:
14546 case 0xA:
14547 case 0xC:
14548 asc_dvc->cfg->termination |= TERM_CTL_H;
14549 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014550
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014551 /* TERM_CTL_H: off, TERM_CTL_L: off */
14552 case 0x2:
14553 case 0x6:
14554 break;
14555 }
14556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014557
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014558 /*
14559 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
14560 */
14561 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014563 /*
14564 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
14565 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
14566 * referenced, because the hardware internally inverts
14567 * the Termination High and Low bits if TERM_POL is set.
14568 */
14569 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014570
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014571 /*
14572 * Set SCSI_CFG1 Microcode Default Value
14573 *
14574 * Set filter value and possibly modified termination control
14575 * bits in the Microcode SCSI_CFG1 Register Value.
14576 *
14577 * The microcode will set the SCSI_CFG1 register using this value
14578 * after it is started below.
14579 */
14580 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14581 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014582
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014583 /*
14584 * Set MEM_CFG Microcode Default Value
14585 *
14586 * The microcode will set the MEM_CFG register using this value
14587 * after it is started below.
14588 *
14589 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14590 * are defined.
14591 *
14592 * ASC-3550 has 8KB internal memory.
14593 */
14594 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14595 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014596
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014597 /*
14598 * Set SEL_MASK Microcode Default Value
14599 *
14600 * The microcode will set the SEL_MASK register using this value
14601 * after it is started below.
14602 */
14603 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14604 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014605
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014606 /*
14607 * Build carrier freelist.
14608 *
14609 * Driver must have already allocated memory and set 'carrier_buf'.
14610 */
14611 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014612
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014613 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14614 asc_dvc->carr_freelist = NULL;
14615 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14616 buf_size = ADV_CARRIER_BUFSIZE;
14617 } else {
14618 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014620
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014621 do {
14622 /*
14623 * Get physical address of the carrier 'carrp'.
14624 */
14625 contig_len = sizeof(ADV_CARR_T);
14626 carr_paddr =
14627 cpu_to_le32(DvcGetPhyAddr
14628 (asc_dvc, NULL, (uchar *)carrp,
14629 (ADV_SDCNT *)&contig_len,
14630 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014631
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014632 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014633
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014634 /*
14635 * If the current carrier is not physically contiguous, then
14636 * maybe there was a page crossing. Try the next carrier aligned
14637 * start address.
14638 */
14639 if (contig_len < sizeof(ADV_CARR_T)) {
14640 carrp++;
14641 continue;
14642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014643
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014644 carrp->carr_pa = carr_paddr;
14645 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014646
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014647 /*
14648 * Insert the carrier at the beginning of the freelist.
14649 */
14650 carrp->next_vpa =
14651 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14652 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014653
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014654 carrp++;
14655 }
14656 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014657
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014658 /*
14659 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14660 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014661
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014662 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14663 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14664 return ADV_ERROR;
14665 }
14666 asc_dvc->carr_freelist = (ADV_CARR_T *)
14667 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014668
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014669 /*
14670 * The first command issued will be placed in the stopper carrier.
14671 */
14672 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014673
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014674 /*
14675 * Set RISC ICQ physical address start value.
14676 */
14677 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014678
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014679 /*
14680 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14681 */
14682 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14683 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14684 return ADV_ERROR;
14685 }
14686 asc_dvc->carr_freelist = (ADV_CARR_T *)
14687 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014688
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014689 /*
14690 * The first command completed by the RISC will be placed in
14691 * the stopper.
14692 *
14693 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14694 * completed the RISC will set the ASC_RQ_STOPPER bit.
14695 */
14696 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014697
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014698 /*
14699 * Set RISC IRQ physical address start value.
14700 */
14701 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14702 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014703
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014704 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14705 (ADV_INTR_ENABLE_HOST_INTR |
14706 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014707
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014708 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14709 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014710
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014711 /* finally, finally, gentlemen, start your engine */
14712 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014713
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014714 /*
14715 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14716 * Resets should be performed. The RISC has to be running
14717 * to issue a SCSI Bus Reset.
14718 */
14719 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14720 /*
14721 * If the BIOS Signature is present in memory, restore the
14722 * BIOS Handshake Configuration Table and do not perform
14723 * a SCSI Bus Reset.
14724 */
14725 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14726 0x55AA) {
14727 /*
14728 * Restore per TID negotiated values.
14729 */
14730 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14731 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14732 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14733 tagqng_able);
14734 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14735 AdvWriteByteLram(iop_base,
14736 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14737 max_cmd[tid]);
14738 }
14739 } else {
14740 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14741 warn_code = ASC_WARN_BUSRESET_ERROR;
14742 }
14743 }
14744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014746 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014747}
14748
14749/*
14750 * Initialize the ASC-38C0800.
14751 *
14752 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14753 *
14754 * For a non-fatal error return a warning code. If there are no warnings
14755 * then 0 is returned.
14756 *
14757 * Needed after initialization for error recovery.
14758 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014759static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014760{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014761 AdvPortAddr iop_base;
14762 ushort warn_code;
14763 ADV_DCNT sum;
14764 int begin_addr;
14765 int end_addr;
14766 ushort code_sum;
14767 int word;
14768 int j;
14769 int adv_asc38C0800_expanded_size;
14770 ADV_CARR_T *carrp;
14771 ADV_DCNT contig_len;
14772 ADV_SDCNT buf_size;
14773 ADV_PADDR carr_paddr;
14774 int i;
14775 ushort scsi_cfg1;
14776 uchar byte;
14777 uchar tid;
14778 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14779 ushort wdtr_able, sdtr_able, tagqng_able;
14780 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014781
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014782 /* If there is already an error, don't continue. */
14783 if (asc_dvc->err_code != 0) {
14784 return ADV_ERROR;
14785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014786
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014787 /*
14788 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14789 */
14790 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14791 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14792 return ADV_ERROR;
14793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014794
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014795 warn_code = 0;
14796 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014797
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014798 /*
14799 * Save the RISC memory BIOS region before writing the microcode.
14800 * The BIOS may already be loaded and using its RISC LRAM region
14801 * so its region must be saved and restored.
14802 *
14803 * Note: This code makes the assumption, which is currently true,
14804 * that a chip reset does not clear RISC LRAM.
14805 */
14806 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14807 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14808 bios_mem[i]);
14809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014810
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014811 /*
14812 * Save current per TID negotiated values.
14813 */
14814 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14815 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14816 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14817 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14818 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14819 max_cmd[tid]);
14820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014821
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014822 /*
14823 * RAM BIST (RAM Built-In Self Test)
14824 *
14825 * Address : I/O base + offset 0x38h register (byte).
14826 * Function: Bit 7-6(RW) : RAM mode
14827 * Normal Mode : 0x00
14828 * Pre-test Mode : 0x40
14829 * RAM Test Mode : 0x80
14830 * Bit 5 : unused
14831 * Bit 4(RO) : Done bit
14832 * Bit 3-0(RO) : Status
14833 * Host Error : 0x08
14834 * Int_RAM Error : 0x04
14835 * RISC Error : 0x02
14836 * SCSI Error : 0x01
14837 * No Error : 0x00
14838 *
14839 * Note: RAM BIST code should be put right here, before loading the
14840 * microcode and after saving the RISC memory BIOS region.
14841 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014842
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014843 /*
14844 * LRAM Pre-test
14845 *
14846 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14847 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14848 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14849 * to NORMAL_MODE, return an error too.
14850 */
14851 for (i = 0; i < 2; i++) {
14852 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14853 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14854 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14855 if ((byte & RAM_TEST_DONE) == 0
14856 || (byte & 0x0F) != PRE_TEST_VALUE) {
14857 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14858 return ADV_ERROR;
14859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014860
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014861 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14862 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14863 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14864 != NORMAL_VALUE) {
14865 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14866 return ADV_ERROR;
14867 }
14868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014869
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014870 /*
14871 * LRAM Test - It takes about 1.5 ms to run through the test.
14872 *
14873 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14874 * If Done bit not set or Status not 0, save register byte, set the
14875 * err_code, and return an error.
14876 */
14877 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14878 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014879
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014880 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14881 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14882 /* Get here if Done bit not set or Status not 0. */
14883 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14884 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14885 return ADV_ERROR;
14886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014887
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014888 /* We need to reset back to normal mode after LRAM test passes. */
14889 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014890
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014891 /*
14892 * Load the Microcode
14893 *
14894 * Write the microcode image to RISC memory starting at address 0.
14895 *
14896 */
14897 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014898
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014899 /* Assume the following compressed format of the microcode buffer:
14900 *
14901 * 254 word (508 byte) table indexed by byte code followed
14902 * by the following byte codes:
14903 *
14904 * 1-Byte Code:
14905 * 00: Emit word 0 in table.
14906 * 01: Emit word 1 in table.
14907 * .
14908 * FD: Emit word 253 in table.
14909 *
14910 * Multi-Byte Code:
14911 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14912 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14913 */
14914 word = 0;
14915 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
14916 if (_adv_asc38C0800_buf[i] == 0xff) {
14917 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
14918 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14919 _adv_asc38C0800_buf
14920 [i +
14921 3] << 8) |
14922 _adv_asc38C0800_buf
14923 [i + 2]));
14924 word++;
14925 }
14926 i += 3;
14927 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
14928 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14929 _adv_asc38C0800_buf
14930 [i +
14931 2] << 8) |
14932 _adv_asc38C0800_buf[i
14933 +
14934 1]));
14935 i += 2;
14936 word++;
14937 } else {
14938 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14939 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
14940 word++;
14941 }
14942 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014943
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014944 /*
14945 * Set 'word' for later use to clear the rest of memory and save
14946 * the expanded mcode size.
14947 */
14948 word *= 2;
14949 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014950
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014951 /*
14952 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
14953 */
14954 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
14955 AdvWriteWordAutoIncLram(iop_base, 0);
14956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014957
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014958 /*
14959 * Verify the microcode checksum.
14960 */
14961 sum = 0;
14962 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014963
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014964 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
14965 sum += AdvReadWordAutoIncLram(iop_base);
14966 }
14967 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014968
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014969 ASC_DBG2(1,
14970 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
14971 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014972
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014973 if (sum != _adv_asc38C0800_chksum) {
14974 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14975 return ADV_ERROR;
14976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014977
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014978 /*
14979 * Restore the RISC memory BIOS region.
14980 */
14981 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14982 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14983 bios_mem[i]);
14984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014985
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014986 /*
14987 * Calculate and write the microcode code checksum to the microcode
14988 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14989 */
14990 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14991 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14992 code_sum = 0;
14993 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14994 for (word = begin_addr; word < end_addr; word += 2) {
14995 code_sum += AdvReadWordAutoIncLram(iop_base);
14996 }
14997 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014998
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014999 /*
15000 * Read microcode version and date.
15001 */
15002 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15003 asc_dvc->cfg->mcode_date);
15004 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15005 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015006
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015007 /*
15008 * Set the chip type to indicate the ASC38C0800.
15009 */
15010 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015011
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015012 /*
15013 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15014 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15015 * cable detection and then we are able to read C_DET[3:0].
15016 *
15017 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15018 * Microcode Default Value' section below.
15019 */
15020 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15021 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15022 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015023
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015024 /*
15025 * If the PCI Configuration Command Register "Parity Error Response
15026 * Control" Bit was clear (0), then set the microcode variable
15027 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15028 * to ignore DMA parity errors.
15029 */
15030 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15031 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15032 word |= CONTROL_FLAG_IGNORE_PERR;
15033 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015035
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015036 /*
15037 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
15038 * bits for the default FIFO threshold.
15039 *
15040 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
15041 *
15042 * For DMA Errata #4 set the BC_THRESH_ENB bit.
15043 */
15044 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15045 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
15046 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015047
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015048 /*
15049 * Microcode operating variables for WDTR, SDTR, and command tag
15050 * queuing will be set in AdvInquiryHandling() based on what a
15051 * device reports it is capable of in Inquiry byte 7.
15052 *
15053 * If SCSI Bus Resets have been disabled, then directly set
15054 * SDTR and WDTR from the EEPROM configuration. This will allow
15055 * the BIOS and warm boot to work without a SCSI bus hang on
15056 * the Inquiry caused by host and target mismatched DTR values.
15057 * Without the SCSI Bus Reset, before an Inquiry a device can't
15058 * be assumed to be in Asynchronous, Narrow mode.
15059 */
15060 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15061 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15062 asc_dvc->wdtr_able);
15063 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15064 asc_dvc->sdtr_able);
15065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015066
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015067 /*
15068 * Set microcode operating variables for DISC and SDTR_SPEED1,
15069 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15070 * configuration values.
15071 *
15072 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15073 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15074 * without determining here whether the device supports SDTR.
15075 */
15076 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15077 asc_dvc->cfg->disc_enable);
15078 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15079 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15080 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15081 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015082
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015083 /*
15084 * Set SCSI_CFG0 Microcode Default Value.
15085 *
15086 * The microcode will set the SCSI_CFG0 register using this value
15087 * after it is started below.
15088 */
15089 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15090 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15091 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015092
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015093 /*
15094 * Determine SCSI_CFG1 Microcode Default Value.
15095 *
15096 * The microcode will set the SCSI_CFG1 register using this value
15097 * after it is started below.
15098 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015099
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015100 /* Read current SCSI_CFG1 Register value. */
15101 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015102
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015103 /*
15104 * If the internal narrow cable is reversed all of the SCSI_CTRL
15105 * register signals will be set. Check for and return an error if
15106 * this condition is found.
15107 */
15108 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15109 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15110 return ADV_ERROR;
15111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015112
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015113 /*
15114 * All kind of combinations of devices attached to one of four connectors
15115 * are acceptable except HVD device attached. For example, LVD device can
15116 * be attached to SE connector while SE device attached to LVD connector.
15117 * If LVD device attached to SE connector, it only runs up to Ultra speed.
15118 *
15119 * If an HVD device is attached to one of LVD connectors, return an error.
15120 * However, there is no way to detect HVD device attached to SE connectors.
15121 */
15122 if (scsi_cfg1 & HVD) {
15123 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15124 return ADV_ERROR;
15125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015126
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015127 /*
15128 * If either SE or LVD automatic termination control is enabled, then
15129 * set the termination value based on a table listed in a_condor.h.
15130 *
15131 * If manual termination was specified with an EEPROM setting then
15132 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
15133 * be 'ored' into SCSI_CFG1.
15134 */
15135 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15136 /* SE automatic termination control is enabled. */
15137 switch (scsi_cfg1 & C_DET_SE) {
15138 /* TERM_SE_HI: on, TERM_SE_LO: on */
15139 case 0x1:
15140 case 0x2:
15141 case 0x3:
15142 asc_dvc->cfg->termination |= TERM_SE;
15143 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015144
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015145 /* TERM_SE_HI: on, TERM_SE_LO: off */
15146 case 0x0:
15147 asc_dvc->cfg->termination |= TERM_SE_HI;
15148 break;
15149 }
15150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015151
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015152 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
15153 /* LVD automatic termination control is enabled. */
15154 switch (scsi_cfg1 & C_DET_LVD) {
15155 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
15156 case 0x4:
15157 case 0x8:
15158 case 0xC:
15159 asc_dvc->cfg->termination |= TERM_LVD;
15160 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015161
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015162 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
15163 case 0x0:
15164 break;
15165 }
15166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015167
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015168 /*
15169 * Clear any set TERM_SE and TERM_LVD bits.
15170 */
15171 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015172
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015173 /*
15174 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
15175 */
15176 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015177
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015178 /*
15179 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
15180 * and set possibly modified termination control bits in the Microcode
15181 * SCSI_CFG1 Register Value.
15182 */
15183 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015184
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015185 /*
15186 * Set SCSI_CFG1 Microcode Default Value
15187 *
15188 * Set possibly modified termination control and reset DIS_TERM_DRV
15189 * bits in the Microcode SCSI_CFG1 Register Value.
15190 *
15191 * The microcode will set the SCSI_CFG1 register using this value
15192 * after it is started below.
15193 */
15194 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015195
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015196 /*
15197 * Set MEM_CFG Microcode Default Value
15198 *
15199 * The microcode will set the MEM_CFG register using this value
15200 * after it is started below.
15201 *
15202 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15203 * are defined.
15204 *
15205 * ASC-38C0800 has 16KB internal memory.
15206 */
15207 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15208 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015209
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015210 /*
15211 * Set SEL_MASK Microcode Default Value
15212 *
15213 * The microcode will set the SEL_MASK register using this value
15214 * after it is started below.
15215 */
15216 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15217 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015218
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015219 /*
15220 * Build the carrier freelist.
15221 *
15222 * Driver must have already allocated memory and set 'carrier_buf'.
15223 */
15224 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015225
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015226 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15227 asc_dvc->carr_freelist = NULL;
15228 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15229 buf_size = ADV_CARRIER_BUFSIZE;
15230 } else {
15231 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015233
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015234 do {
15235 /*
15236 * Get physical address for the carrier 'carrp'.
15237 */
15238 contig_len = sizeof(ADV_CARR_T);
15239 carr_paddr =
15240 cpu_to_le32(DvcGetPhyAddr
15241 (asc_dvc, NULL, (uchar *)carrp,
15242 (ADV_SDCNT *)&contig_len,
15243 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015244
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015245 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015246
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015247 /*
15248 * If the current carrier is not physically contiguous, then
15249 * maybe there was a page crossing. Try the next carrier aligned
15250 * start address.
15251 */
15252 if (contig_len < sizeof(ADV_CARR_T)) {
15253 carrp++;
15254 continue;
15255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015256
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015257 carrp->carr_pa = carr_paddr;
15258 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015259
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015260 /*
15261 * Insert the carrier at the beginning of the freelist.
15262 */
15263 carrp->next_vpa =
15264 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15265 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015266
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015267 carrp++;
15268 }
15269 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015270
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015271 /*
15272 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15273 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015274
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015275 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15276 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15277 return ADV_ERROR;
15278 }
15279 asc_dvc->carr_freelist = (ADV_CARR_T *)
15280 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015281
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015282 /*
15283 * The first command issued will be placed in the stopper carrier.
15284 */
15285 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015286
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015287 /*
15288 * Set RISC ICQ physical address start value.
15289 * carr_pa is LE, must be native before write
15290 */
15291 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015292
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015293 /*
15294 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15295 */
15296 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15297 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15298 return ADV_ERROR;
15299 }
15300 asc_dvc->carr_freelist = (ADV_CARR_T *)
15301 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015302
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015303 /*
15304 * The first command completed by the RISC will be placed in
15305 * the stopper.
15306 *
15307 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15308 * completed the RISC will set the ASC_RQ_STOPPER bit.
15309 */
15310 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015311
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015312 /*
15313 * Set RISC IRQ physical address start value.
15314 *
15315 * carr_pa is LE, must be native before write *
15316 */
15317 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15318 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015319
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015320 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15321 (ADV_INTR_ENABLE_HOST_INTR |
15322 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015323
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015324 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15325 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015326
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015327 /* finally, finally, gentlemen, start your engine */
15328 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015329
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015330 /*
15331 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15332 * Resets should be performed. The RISC has to be running
15333 * to issue a SCSI Bus Reset.
15334 */
15335 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15336 /*
15337 * If the BIOS Signature is present in memory, restore the
15338 * BIOS Handshake Configuration Table and do not perform
15339 * a SCSI Bus Reset.
15340 */
15341 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15342 0x55AA) {
15343 /*
15344 * Restore per TID negotiated values.
15345 */
15346 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15347 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15348 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15349 tagqng_able);
15350 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15351 AdvWriteByteLram(iop_base,
15352 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15353 max_cmd[tid]);
15354 }
15355 } else {
15356 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15357 warn_code = ASC_WARN_BUSRESET_ERROR;
15358 }
15359 }
15360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015361
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015362 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015363}
15364
15365/*
15366 * Initialize the ASC-38C1600.
15367 *
15368 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15369 *
15370 * For a non-fatal error return a warning code. If there are no warnings
15371 * then 0 is returned.
15372 *
15373 * Needed after initialization for error recovery.
15374 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015375static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015376{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015377 AdvPortAddr iop_base;
15378 ushort warn_code;
15379 ADV_DCNT sum;
15380 int begin_addr;
15381 int end_addr;
15382 ushort code_sum;
15383 long word;
15384 int j;
15385 int adv_asc38C1600_expanded_size;
15386 ADV_CARR_T *carrp;
15387 ADV_DCNT contig_len;
15388 ADV_SDCNT buf_size;
15389 ADV_PADDR carr_paddr;
15390 int i;
15391 ushort scsi_cfg1;
15392 uchar byte;
15393 uchar tid;
15394 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
15395 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
15396 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070015397
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015398 /* If there is already an error, don't continue. */
15399 if (asc_dvc->err_code != 0) {
15400 return ADV_ERROR;
15401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015402
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015403 /*
15404 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
15405 */
15406 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
15407 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
15408 return ADV_ERROR;
15409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015410
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015411 warn_code = 0;
15412 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015413
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015414 /*
15415 * Save the RISC memory BIOS region before writing the microcode.
15416 * The BIOS may already be loaded and using its RISC LRAM region
15417 * so its region must be saved and restored.
15418 *
15419 * Note: This code makes the assumption, which is currently true,
15420 * that a chip reset does not clear RISC LRAM.
15421 */
15422 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15423 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15424 bios_mem[i]);
15425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015426
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015427 /*
15428 * Save current per TID negotiated values.
15429 */
15430 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15431 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15432 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15433 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
15434 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15435 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
15436 max_cmd[tid]);
15437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015438
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015439 /*
15440 * RAM BIST (Built-In Self Test)
15441 *
15442 * Address : I/O base + offset 0x38h register (byte).
15443 * Function: Bit 7-6(RW) : RAM mode
15444 * Normal Mode : 0x00
15445 * Pre-test Mode : 0x40
15446 * RAM Test Mode : 0x80
15447 * Bit 5 : unused
15448 * Bit 4(RO) : Done bit
15449 * Bit 3-0(RO) : Status
15450 * Host Error : 0x08
15451 * Int_RAM Error : 0x04
15452 * RISC Error : 0x02
15453 * SCSI Error : 0x01
15454 * No Error : 0x00
15455 *
15456 * Note: RAM BIST code should be put right here, before loading the
15457 * microcode and after saving the RISC memory BIOS region.
15458 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015459
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015460 /*
15461 * LRAM Pre-test
15462 *
15463 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
15464 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
15465 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
15466 * to NORMAL_MODE, return an error too.
15467 */
15468 for (i = 0; i < 2; i++) {
15469 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
15470 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15471 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15472 if ((byte & RAM_TEST_DONE) == 0
15473 || (byte & 0x0F) != PRE_TEST_VALUE) {
15474 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15475 return ADV_ERROR;
15476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015477
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015478 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
15479 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15480 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
15481 != NORMAL_VALUE) {
15482 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15483 return ADV_ERROR;
15484 }
15485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015486
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015487 /*
15488 * LRAM Test - It takes about 1.5 ms to run through the test.
15489 *
15490 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
15491 * If Done bit not set or Status not 0, save register byte, set the
15492 * err_code, and return an error.
15493 */
15494 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
15495 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015496
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015497 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15498 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
15499 /* Get here if Done bit not set or Status not 0. */
15500 asc_dvc->bist_err_code = byte; /* for BIOS display message */
15501 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
15502 return ADV_ERROR;
15503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015504
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015505 /* We need to reset back to normal mode after LRAM test passes. */
15506 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015507
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015508 /*
15509 * Load the Microcode
15510 *
15511 * Write the microcode image to RISC memory starting at address 0.
15512 *
15513 */
15514 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015515
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015516 /*
15517 * Assume the following compressed format of the microcode buffer:
15518 *
15519 * 254 word (508 byte) table indexed by byte code followed
15520 * by the following byte codes:
15521 *
15522 * 1-Byte Code:
15523 * 00: Emit word 0 in table.
15524 * 01: Emit word 1 in table.
15525 * .
15526 * FD: Emit word 253 in table.
15527 *
15528 * Multi-Byte Code:
15529 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15530 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15531 */
15532 word = 0;
15533 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
15534 if (_adv_asc38C1600_buf[i] == 0xff) {
15535 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
15536 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15537 _adv_asc38C1600_buf
15538 [i +
15539 3] << 8) |
15540 _adv_asc38C1600_buf
15541 [i + 2]));
15542 word++;
15543 }
15544 i += 3;
15545 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
15546 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15547 _adv_asc38C1600_buf
15548 [i +
15549 2] << 8) |
15550 _adv_asc38C1600_buf[i
15551 +
15552 1]));
15553 i += 2;
15554 word++;
15555 } else {
15556 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15557 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
15558 word++;
15559 }
15560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015561
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015562 /*
15563 * Set 'word' for later use to clear the rest of memory and save
15564 * the expanded mcode size.
15565 */
15566 word *= 2;
15567 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015568
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015569 /*
15570 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15571 */
15572 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15573 AdvWriteWordAutoIncLram(iop_base, 0);
15574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015575
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015576 /*
15577 * Verify the microcode checksum.
15578 */
15579 sum = 0;
15580 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015581
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015582 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15583 sum += AdvReadWordAutoIncLram(iop_base);
15584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015585
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015586 if (sum != _adv_asc38C1600_chksum) {
15587 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15588 return ADV_ERROR;
15589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015590
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015591 /*
15592 * Restore the RISC memory BIOS region.
15593 */
15594 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15595 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15596 bios_mem[i]);
15597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015598
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015599 /*
15600 * Calculate and write the microcode code checksum to the microcode
15601 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15602 */
15603 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15604 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15605 code_sum = 0;
15606 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15607 for (word = begin_addr; word < end_addr; word += 2) {
15608 code_sum += AdvReadWordAutoIncLram(iop_base);
15609 }
15610 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015611
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015612 /*
15613 * Read microcode version and date.
15614 */
15615 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15616 asc_dvc->cfg->mcode_date);
15617 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15618 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015619
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015620 /*
15621 * Set the chip type to indicate the ASC38C1600.
15622 */
15623 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015624
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015625 /*
15626 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15627 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15628 * cable detection and then we are able to read C_DET[3:0].
15629 *
15630 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15631 * Microcode Default Value' section below.
15632 */
15633 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15634 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15635 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015636
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015637 /*
15638 * If the PCI Configuration Command Register "Parity Error Response
15639 * Control" Bit was clear (0), then set the microcode variable
15640 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15641 * to ignore DMA parity errors.
15642 */
15643 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15644 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15645 word |= CONTROL_FLAG_IGNORE_PERR;
15646 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015649 /*
15650 * If the BIOS control flag AIPP (Asynchronous Information
15651 * Phase Protection) disable bit is not set, then set the firmware
15652 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15653 * AIPP checking and encoding.
15654 */
15655 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15656 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15657 word |= CONTROL_FLAG_ENABLE_AIPP;
15658 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015660
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015661 /*
15662 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15663 * and START_CTL_TH [3:2].
15664 */
15665 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15666 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015667
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015668 /*
15669 * Microcode operating variables for WDTR, SDTR, and command tag
15670 * queuing will be set in AdvInquiryHandling() based on what a
15671 * device reports it is capable of in Inquiry byte 7.
15672 *
15673 * If SCSI Bus Resets have been disabled, then directly set
15674 * SDTR and WDTR from the EEPROM configuration. This will allow
15675 * the BIOS and warm boot to work without a SCSI bus hang on
15676 * the Inquiry caused by host and target mismatched DTR values.
15677 * Without the SCSI Bus Reset, before an Inquiry a device can't
15678 * be assumed to be in Asynchronous, Narrow mode.
15679 */
15680 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15681 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15682 asc_dvc->wdtr_able);
15683 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15684 asc_dvc->sdtr_able);
15685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015686
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015687 /*
15688 * Set microcode operating variables for DISC and SDTR_SPEED1,
15689 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15690 * configuration values.
15691 *
15692 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15693 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15694 * without determining here whether the device supports SDTR.
15695 */
15696 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15697 asc_dvc->cfg->disc_enable);
15698 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15699 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15700 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15701 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015702
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015703 /*
15704 * Set SCSI_CFG0 Microcode Default Value.
15705 *
15706 * The microcode will set the SCSI_CFG0 register using this value
15707 * after it is started below.
15708 */
15709 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15710 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15711 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015712
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015713 /*
15714 * Calculate SCSI_CFG1 Microcode Default Value.
15715 *
15716 * The microcode will set the SCSI_CFG1 register using this value
15717 * after it is started below.
15718 *
15719 * Each ASC-38C1600 function has only two cable detect bits.
15720 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15721 */
15722 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015723
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015724 /*
15725 * If the cable is reversed all of the SCSI_CTRL register signals
15726 * will be set. Check for and return an error if this condition is
15727 * found.
15728 */
15729 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15730 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15731 return ADV_ERROR;
15732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015733
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015734 /*
15735 * Each ASC-38C1600 function has two connectors. Only an HVD device
15736 * can not be connected to either connector. An LVD device or SE device
15737 * may be connected to either connecor. If an SE device is connected,
15738 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15739 *
15740 * If an HVD device is attached, return an error.
15741 */
15742 if (scsi_cfg1 & HVD) {
15743 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15744 return ADV_ERROR;
15745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015746
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015747 /*
15748 * Each function in the ASC-38C1600 uses only the SE cable detect and
15749 * termination because there are two connectors for each function. Each
15750 * function may use either LVD or SE mode. Corresponding the SE automatic
15751 * termination control EEPROM bits are used for each function. Each
15752 * function has its own EEPROM. If SE automatic control is enabled for
15753 * the function, then set the termination value based on a table listed
15754 * in a_condor.h.
15755 *
15756 * If manual termination is specified in the EEPROM for the function,
15757 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15758 * ready to be 'ored' into SCSI_CFG1.
15759 */
15760 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15761 /* SE automatic termination control is enabled. */
15762 switch (scsi_cfg1 & C_DET_SE) {
15763 /* TERM_SE_HI: on, TERM_SE_LO: on */
15764 case 0x1:
15765 case 0x2:
15766 case 0x3:
15767 asc_dvc->cfg->termination |= TERM_SE;
15768 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015770 case 0x0:
15771 if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
15772 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15773 } else {
15774 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15775 asc_dvc->cfg->termination |= TERM_SE_HI;
15776 }
15777 break;
15778 }
15779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015781 /*
15782 * Clear any set TERM_SE bits.
15783 */
15784 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015785
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015786 /*
15787 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15788 */
15789 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015790
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015791 /*
15792 * Clear Big Endian and Terminator Polarity bits and set possibly
15793 * modified termination control bits in the Microcode SCSI_CFG1
15794 * Register Value.
15795 *
15796 * Big Endian bit is not used even on big endian machines.
15797 */
15798 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015799
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015800 /*
15801 * Set SCSI_CFG1 Microcode Default Value
15802 *
15803 * Set possibly modified termination control bits in the Microcode
15804 * SCSI_CFG1 Register Value.
15805 *
15806 * The microcode will set the SCSI_CFG1 register using this value
15807 * after it is started below.
15808 */
15809 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015810
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015811 /*
15812 * Set MEM_CFG Microcode Default Value
15813 *
15814 * The microcode will set the MEM_CFG register using this value
15815 * after it is started below.
15816 *
15817 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15818 * are defined.
15819 *
15820 * ASC-38C1600 has 32KB internal memory.
15821 *
15822 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15823 * out a special 16K Adv Library and Microcode version. After the issue
15824 * resolved, we should turn back to the 32K support. Both a_condor.h and
15825 * mcode.sas files also need to be updated.
15826 *
15827 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15828 * BIOS_EN | RAM_SZ_32KB);
15829 */
15830 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15831 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015832
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015833 /*
15834 * Set SEL_MASK Microcode Default Value
15835 *
15836 * The microcode will set the SEL_MASK register using this value
15837 * after it is started below.
15838 */
15839 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15840 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015841
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015842 /*
15843 * Build the carrier freelist.
15844 *
15845 * Driver must have already allocated memory and set 'carrier_buf'.
15846 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015847
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015848 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015849
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015850 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15851 asc_dvc->carr_freelist = NULL;
15852 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15853 buf_size = ADV_CARRIER_BUFSIZE;
15854 } else {
15855 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015857
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015858 do {
15859 /*
15860 * Get physical address for the carrier 'carrp'.
15861 */
15862 contig_len = sizeof(ADV_CARR_T);
15863 carr_paddr =
15864 cpu_to_le32(DvcGetPhyAddr
15865 (asc_dvc, NULL, (uchar *)carrp,
15866 (ADV_SDCNT *)&contig_len,
15867 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015868
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015869 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015870
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015871 /*
15872 * If the current carrier is not physically contiguous, then
15873 * maybe there was a page crossing. Try the next carrier aligned
15874 * start address.
15875 */
15876 if (contig_len < sizeof(ADV_CARR_T)) {
15877 carrp++;
15878 continue;
15879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015880
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015881 carrp->carr_pa = carr_paddr;
15882 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015883
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015884 /*
15885 * Insert the carrier at the beginning of the freelist.
15886 */
15887 carrp->next_vpa =
15888 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15889 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015890
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015891 carrp++;
15892 }
15893 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015894
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015895 /*
15896 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15897 */
15898 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15899 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15900 return ADV_ERROR;
15901 }
15902 asc_dvc->carr_freelist = (ADV_CARR_T *)
15903 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015904
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015905 /*
15906 * The first command issued will be placed in the stopper carrier.
15907 */
15908 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015909
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015910 /*
15911 * Set RISC ICQ physical address start value. Initialize the
15912 * COMMA register to the same value otherwise the RISC will
15913 * prematurely detect a command is available.
15914 */
15915 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
15916 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
15917 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015918
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015919 /*
15920 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15921 */
15922 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15923 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15924 return ADV_ERROR;
15925 }
15926 asc_dvc->carr_freelist = (ADV_CARR_T *)
15927 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015928
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015929 /*
15930 * The first command completed by the RISC will be placed in
15931 * the stopper.
15932 *
15933 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15934 * completed the RISC will set the ASC_RQ_STOPPER bit.
15935 */
15936 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015937
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015938 /*
15939 * Set RISC IRQ physical address start value.
15940 */
15941 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15942 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015943
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015944 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15945 (ADV_INTR_ENABLE_HOST_INTR |
15946 ADV_INTR_ENABLE_GLOBAL_INTR));
15947 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15948 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015949
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015950 /* finally, finally, gentlemen, start your engine */
15951 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015952
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015953 /*
15954 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15955 * Resets should be performed. The RISC has to be running
15956 * to issue a SCSI Bus Reset.
15957 */
15958 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15959 /*
15960 * If the BIOS Signature is present in memory, restore the
15961 * per TID microcode operating variables.
15962 */
15963 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15964 0x55AA) {
15965 /*
15966 * Restore per TID negotiated values.
15967 */
15968 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15969 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15970 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15971 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15972 tagqng_able);
15973 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15974 AdvWriteByteLram(iop_base,
15975 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15976 max_cmd[tid]);
15977 }
15978 } else {
15979 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15980 warn_code = ASC_WARN_BUSRESET_ERROR;
15981 }
15982 }
15983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015984
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015985 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015986}
15987
15988/*
15989 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15990 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15991 * all of this is done.
15992 *
15993 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15994 *
15995 * For a non-fatal error return a warning code. If there are no warnings
15996 * then 0 is returned.
15997 *
15998 * Note: Chip is stopped on entry.
15999 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016000static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016001{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016002 AdvPortAddr iop_base;
16003 ushort warn_code;
16004 ADVEEP_3550_CONFIG eep_config;
16005 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016006
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016007 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016008
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016009 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016011 /*
16012 * Read the board's EEPROM configuration.
16013 *
16014 * Set default values if a bad checksum is found.
16015 */
16016 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
16017 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016018
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016019 /*
16020 * Set EEPROM default values.
16021 */
16022 for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
16023 *((uchar *)&eep_config + i) =
16024 *((uchar *)&Default_3550_EEPROM_Config + i);
16025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016026
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016027 /*
16028 * Assume the 6 byte board serial number that was read
16029 * from EEPROM is correct even if the EEPROM checksum
16030 * failed.
16031 */
16032 eep_config.serial_number_word3 =
16033 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016034
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016035 eep_config.serial_number_word2 =
16036 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016037
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016038 eep_config.serial_number_word1 =
16039 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016040
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016041 AdvSet3550EEPConfig(iop_base, &eep_config);
16042 }
16043 /*
16044 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
16045 * EEPROM configuration that was read.
16046 *
16047 * This is the mapping of EEPROM fields to Adv Library fields.
16048 */
16049 asc_dvc->wdtr_able = eep_config.wdtr_able;
16050 asc_dvc->sdtr_able = eep_config.sdtr_able;
16051 asc_dvc->ultra_able = eep_config.ultra_able;
16052 asc_dvc->tagqng_able = eep_config.tagqng_able;
16053 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16054 asc_dvc->max_host_qng = eep_config.max_host_qng;
16055 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16056 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
16057 asc_dvc->start_motor = eep_config.start_motor;
16058 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16059 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16060 asc_dvc->no_scam = eep_config.scam_tolerant;
16061 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
16062 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
16063 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016064
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016065 /*
16066 * Set the host maximum queuing (max. 253, min. 16) and the per device
16067 * maximum queuing (max. 63, min. 4).
16068 */
16069 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16070 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16071 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16072 /* If the value is zero, assume it is uninitialized. */
16073 if (eep_config.max_host_qng == 0) {
16074 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16075 } else {
16076 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16077 }
16078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016079
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016080 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16081 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16082 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16083 /* If the value is zero, assume it is uninitialized. */
16084 if (eep_config.max_dvc_qng == 0) {
16085 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16086 } else {
16087 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16088 }
16089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016090
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016091 /*
16092 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16093 * set 'max_dvc_qng' to 'max_host_qng'.
16094 */
16095 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16096 eep_config.max_dvc_qng = eep_config.max_host_qng;
16097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016098
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016099 /*
16100 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
16101 * values based on possibly adjusted EEPROM values.
16102 */
16103 asc_dvc->max_host_qng = eep_config.max_host_qng;
16104 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016105
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016106 /*
16107 * If the EEPROM 'termination' field is set to automatic (0), then set
16108 * the ADV_DVC_CFG 'termination' field to automatic also.
16109 *
16110 * If the termination is specified with a non-zero 'termination'
16111 * value check that a legal value is set and set the ADV_DVC_CFG
16112 * 'termination' field appropriately.
16113 */
16114 if (eep_config.termination == 0) {
16115 asc_dvc->cfg->termination = 0; /* auto termination */
16116 } else {
16117 /* Enable manual control with low off / high off. */
16118 if (eep_config.termination == 1) {
16119 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016120
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016121 /* Enable manual control with low off / high on. */
16122 } else if (eep_config.termination == 2) {
16123 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016124
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016125 /* Enable manual control with low on / high on. */
16126 } else if (eep_config.termination == 3) {
16127 asc_dvc->cfg->termination =
16128 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
16129 } else {
16130 /*
16131 * The EEPROM 'termination' field contains a bad value. Use
16132 * automatic termination instead.
16133 */
16134 asc_dvc->cfg->termination = 0;
16135 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16136 }
16137 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016138
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016139 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016140}
16141
16142/*
16143 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
16144 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
16145 * all of this is done.
16146 *
16147 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
16148 *
16149 * For a non-fatal error return a warning code. If there are no warnings
16150 * then 0 is returned.
16151 *
16152 * Note: Chip is stopped on entry.
16153 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016154static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016155{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016156 AdvPortAddr iop_base;
16157 ushort warn_code;
16158 ADVEEP_38C0800_CONFIG eep_config;
16159 int i;
16160 uchar tid, termination;
16161 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016162
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016163 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016164
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016165 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016166
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016167 /*
16168 * Read the board's EEPROM configuration.
16169 *
16170 * Set default values if a bad checksum is found.
16171 */
16172 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
16173 eep_config.check_sum) {
16174 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016176 /*
16177 * Set EEPROM default values.
16178 */
16179 for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
16180 *((uchar *)&eep_config + i) =
16181 *((uchar *)&Default_38C0800_EEPROM_Config + i);
16182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016183
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016184 /*
16185 * Assume the 6 byte board serial number that was read
16186 * from EEPROM is correct even if the EEPROM checksum
16187 * failed.
16188 */
16189 eep_config.serial_number_word3 =
16190 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016191
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016192 eep_config.serial_number_word2 =
16193 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016194
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016195 eep_config.serial_number_word1 =
16196 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016197
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016198 AdvSet38C0800EEPConfig(iop_base, &eep_config);
16199 }
16200 /*
16201 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
16202 * EEPROM configuration that was read.
16203 *
16204 * This is the mapping of EEPROM fields to Adv Library fields.
16205 */
16206 asc_dvc->wdtr_able = eep_config.wdtr_able;
16207 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
16208 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
16209 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
16210 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
16211 asc_dvc->tagqng_able = eep_config.tagqng_able;
16212 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16213 asc_dvc->max_host_qng = eep_config.max_host_qng;
16214 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16215 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
16216 asc_dvc->start_motor = eep_config.start_motor;
16217 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16218 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16219 asc_dvc->no_scam = eep_config.scam_tolerant;
16220 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
16221 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
16222 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016223
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016224 /*
16225 * For every Target ID if any of its 'sdtr_speed[1234]' bits
16226 * are set, then set an 'sdtr_able' bit for it.
16227 */
16228 asc_dvc->sdtr_able = 0;
16229 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16230 if (tid == 0) {
16231 sdtr_speed = asc_dvc->sdtr_speed1;
16232 } else if (tid == 4) {
16233 sdtr_speed = asc_dvc->sdtr_speed2;
16234 } else if (tid == 8) {
16235 sdtr_speed = asc_dvc->sdtr_speed3;
16236 } else if (tid == 12) {
16237 sdtr_speed = asc_dvc->sdtr_speed4;
16238 }
16239 if (sdtr_speed & ADV_MAX_TID) {
16240 asc_dvc->sdtr_able |= (1 << tid);
16241 }
16242 sdtr_speed >>= 4;
16243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016244
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016245 /*
16246 * Set the host maximum queuing (max. 253, min. 16) and the per device
16247 * maximum queuing (max. 63, min. 4).
16248 */
16249 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16250 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16251 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16252 /* If the value is zero, assume it is uninitialized. */
16253 if (eep_config.max_host_qng == 0) {
16254 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16255 } else {
16256 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16257 }
16258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016259
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016260 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16261 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16262 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16263 /* If the value is zero, assume it is uninitialized. */
16264 if (eep_config.max_dvc_qng == 0) {
16265 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16266 } else {
16267 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16268 }
16269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016270
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016271 /*
16272 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16273 * set 'max_dvc_qng' to 'max_host_qng'.
16274 */
16275 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16276 eep_config.max_dvc_qng = eep_config.max_host_qng;
16277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016278
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016279 /*
16280 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
16281 * values based on possibly adjusted EEPROM values.
16282 */
16283 asc_dvc->max_host_qng = eep_config.max_host_qng;
16284 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016285
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016286 /*
16287 * If the EEPROM 'termination' field is set to automatic (0), then set
16288 * the ADV_DVC_CFG 'termination' field to automatic also.
16289 *
16290 * If the termination is specified with a non-zero 'termination'
16291 * value check that a legal value is set and set the ADV_DVC_CFG
16292 * 'termination' field appropriately.
16293 */
16294 if (eep_config.termination_se == 0) {
16295 termination = 0; /* auto termination for SE */
16296 } else {
16297 /* Enable manual control with low off / high off. */
16298 if (eep_config.termination_se == 1) {
16299 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016300
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016301 /* Enable manual control with low off / high on. */
16302 } else if (eep_config.termination_se == 2) {
16303 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016304
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016305 /* Enable manual control with low on / high on. */
16306 } else if (eep_config.termination_se == 3) {
16307 termination = TERM_SE;
16308 } else {
16309 /*
16310 * The EEPROM 'termination_se' field contains a bad value.
16311 * Use automatic termination instead.
16312 */
16313 termination = 0;
16314 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16315 }
16316 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016317
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016318 if (eep_config.termination_lvd == 0) {
16319 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16320 } else {
16321 /* Enable manual control with low off / high off. */
16322 if (eep_config.termination_lvd == 1) {
16323 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016324
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016325 /* Enable manual control with low off / high on. */
16326 } else if (eep_config.termination_lvd == 2) {
16327 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016328
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016329 /* Enable manual control with low on / high on. */
16330 } else if (eep_config.termination_lvd == 3) {
16331 asc_dvc->cfg->termination = termination | TERM_LVD;
16332 } else {
16333 /*
16334 * The EEPROM 'termination_lvd' field contains a bad value.
16335 * Use automatic termination instead.
16336 */
16337 asc_dvc->cfg->termination = termination;
16338 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16339 }
16340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016341
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016342 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016343}
16344
16345/*
16346 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
16347 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
16348 * all of this is done.
16349 *
16350 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
16351 *
16352 * For a non-fatal error return a warning code. If there are no warnings
16353 * then 0 is returned.
16354 *
16355 * Note: Chip is stopped on entry.
16356 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016357static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016358{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016359 AdvPortAddr iop_base;
16360 ushort warn_code;
16361 ADVEEP_38C1600_CONFIG eep_config;
16362 int i;
16363 uchar tid, termination;
16364 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016365
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016366 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016367
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016368 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016369
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016370 /*
16371 * Read the board's EEPROM configuration.
16372 *
16373 * Set default values if a bad checksum is found.
16374 */
16375 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
16376 eep_config.check_sum) {
16377 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016378
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016379 /*
16380 * Set EEPROM default values.
16381 */
16382 for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
16383 if (i == 1
16384 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
16385 0) {
16386 /*
16387 * Set Function 1 EEPROM Word 0 MSB
16388 *
16389 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
16390 * EEPROM bits.
16391 *
16392 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
16393 * old Mac system booting problem. The Expansion ROM must
16394 * be disabled in Function 1 for these systems.
16395 *
16396 */
16397 *((uchar *)&eep_config + i) =
16398 ((*
16399 ((uchar *)&Default_38C1600_EEPROM_Config
16400 +
16401 i)) &
16402 (~
16403 (((ADV_EEPROM_BIOS_ENABLE |
16404 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016405
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016406 /*
16407 * Set the INTAB (bit 11) if the GPIO 0 input indicates
16408 * the Function 1 interrupt line is wired to INTA.
16409 *
16410 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
16411 * 1 - Function 1 interrupt line wired to INT A.
16412 * 0 - Function 1 interrupt line wired to INT B.
16413 *
16414 * Note: Adapter boards always have Function 0 wired to INTA.
16415 * Put all 5 GPIO bits in input mode and then read
16416 * their input values.
16417 */
16418 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
16419 0);
16420 if (AdvReadByteRegister
16421 (iop_base, IOPB_GPIO_DATA) & 0x01) {
16422 /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
16423 *((uchar *)&eep_config + i) |=
16424 ((ADV_EEPROM_INTAB >> 8) & 0xFF);
16425 }
16426 } else {
16427 *((uchar *)&eep_config + i) =
16428 *((uchar *)&Default_38C1600_EEPROM_Config
16429 + i);
16430 }
16431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016432
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016433 /*
16434 * Assume the 6 byte board serial number that was read
16435 * from EEPROM is correct even if the EEPROM checksum
16436 * failed.
16437 */
16438 eep_config.serial_number_word3 =
16439 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016441 eep_config.serial_number_word2 =
16442 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016443
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016444 eep_config.serial_number_word1 =
16445 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016446
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016447 AdvSet38C1600EEPConfig(iop_base, &eep_config);
16448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016449
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016450 /*
16451 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
16452 * EEPROM configuration that was read.
16453 *
16454 * This is the mapping of EEPROM fields to Adv Library fields.
16455 */
16456 asc_dvc->wdtr_able = eep_config.wdtr_able;
16457 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
16458 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
16459 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
16460 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
16461 asc_dvc->ppr_able = 0;
16462 asc_dvc->tagqng_able = eep_config.tagqng_able;
16463 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16464 asc_dvc->max_host_qng = eep_config.max_host_qng;
16465 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16466 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
16467 asc_dvc->start_motor = eep_config.start_motor;
16468 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16469 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16470 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016471
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016472 /*
16473 * For every Target ID if any of its 'sdtr_speed[1234]' bits
16474 * are set, then set an 'sdtr_able' bit for it.
16475 */
16476 asc_dvc->sdtr_able = 0;
16477 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
16478 if (tid == 0) {
16479 sdtr_speed = asc_dvc->sdtr_speed1;
16480 } else if (tid == 4) {
16481 sdtr_speed = asc_dvc->sdtr_speed2;
16482 } else if (tid == 8) {
16483 sdtr_speed = asc_dvc->sdtr_speed3;
16484 } else if (tid == 12) {
16485 sdtr_speed = asc_dvc->sdtr_speed4;
16486 }
16487 if (sdtr_speed & ASC_MAX_TID) {
16488 asc_dvc->sdtr_able |= (1 << tid);
16489 }
16490 sdtr_speed >>= 4;
16491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016492
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016493 /*
16494 * Set the host maximum queuing (max. 253, min. 16) and the per device
16495 * maximum queuing (max. 63, min. 4).
16496 */
16497 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16498 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16499 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16500 /* If the value is zero, assume it is uninitialized. */
16501 if (eep_config.max_host_qng == 0) {
16502 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16503 } else {
16504 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16505 }
16506 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016507
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016508 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16509 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16510 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16511 /* If the value is zero, assume it is uninitialized. */
16512 if (eep_config.max_dvc_qng == 0) {
16513 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16514 } else {
16515 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16516 }
16517 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016518
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016519 /*
16520 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16521 * set 'max_dvc_qng' to 'max_host_qng'.
16522 */
16523 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16524 eep_config.max_dvc_qng = eep_config.max_host_qng;
16525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016526
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016527 /*
16528 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
16529 * values based on possibly adjusted EEPROM values.
16530 */
16531 asc_dvc->max_host_qng = eep_config.max_host_qng;
16532 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016533
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016534 /*
16535 * If the EEPROM 'termination' field is set to automatic (0), then set
16536 * the ASC_DVC_CFG 'termination' field to automatic also.
16537 *
16538 * If the termination is specified with a non-zero 'termination'
16539 * value check that a legal value is set and set the ASC_DVC_CFG
16540 * 'termination' field appropriately.
16541 */
16542 if (eep_config.termination_se == 0) {
16543 termination = 0; /* auto termination for SE */
16544 } else {
16545 /* Enable manual control with low off / high off. */
16546 if (eep_config.termination_se == 1) {
16547 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016548
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016549 /* Enable manual control with low off / high on. */
16550 } else if (eep_config.termination_se == 2) {
16551 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016552
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016553 /* Enable manual control with low on / high on. */
16554 } else if (eep_config.termination_se == 3) {
16555 termination = TERM_SE;
16556 } else {
16557 /*
16558 * The EEPROM 'termination_se' field contains a bad value.
16559 * Use automatic termination instead.
16560 */
16561 termination = 0;
16562 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16563 }
16564 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016565
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016566 if (eep_config.termination_lvd == 0) {
16567 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16568 } else {
16569 /* Enable manual control with low off / high off. */
16570 if (eep_config.termination_lvd == 1) {
16571 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016572
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016573 /* Enable manual control with low off / high on. */
16574 } else if (eep_config.termination_lvd == 2) {
16575 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016577 /* Enable manual control with low on / high on. */
16578 } else if (eep_config.termination_lvd == 3) {
16579 asc_dvc->cfg->termination = termination | TERM_LVD;
16580 } else {
16581 /*
16582 * The EEPROM 'termination_lvd' field contains a bad value.
16583 * Use automatic termination instead.
16584 */
16585 asc_dvc->cfg->termination = termination;
16586 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16587 }
16588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016589
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016590 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016591}
16592
16593/*
16594 * Read EEPROM configuration into the specified buffer.
16595 *
16596 * Return a checksum based on the EEPROM configuration read.
16597 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016598static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016599AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16600{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016601 ushort wval, chksum;
16602 ushort *wbuf;
16603 int eep_addr;
16604 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016605
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016606 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16607 wbuf = (ushort *)cfg_buf;
16608 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016609
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016610 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16611 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16612 wval = AdvReadEEPWord(iop_base, eep_addr);
16613 chksum += wval; /* Checksum is calculated from word values. */
16614 if (*charfields++) {
16615 *wbuf = le16_to_cpu(wval);
16616 } else {
16617 *wbuf = wval;
16618 }
16619 }
16620 /* Read checksum word. */
16621 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16622 wbuf++;
16623 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016624
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016625 /* Read rest of EEPROM not covered by the checksum. */
16626 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16627 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16628 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16629 if (*charfields++) {
16630 *wbuf = le16_to_cpu(*wbuf);
16631 }
16632 }
16633 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016634}
16635
16636/*
16637 * Read EEPROM configuration into the specified buffer.
16638 *
16639 * Return a checksum based on the EEPROM configuration read.
16640 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016641static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016642AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016643{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016644 ushort wval, chksum;
16645 ushort *wbuf;
16646 int eep_addr;
16647 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016649 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16650 wbuf = (ushort *)cfg_buf;
16651 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016653 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16654 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16655 wval = AdvReadEEPWord(iop_base, eep_addr);
16656 chksum += wval; /* Checksum is calculated from word values. */
16657 if (*charfields++) {
16658 *wbuf = le16_to_cpu(wval);
16659 } else {
16660 *wbuf = wval;
16661 }
16662 }
16663 /* Read checksum word. */
16664 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16665 wbuf++;
16666 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016667
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016668 /* Read rest of EEPROM not covered by the checksum. */
16669 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16670 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16671 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16672 if (*charfields++) {
16673 *wbuf = le16_to_cpu(*wbuf);
16674 }
16675 }
16676 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016677}
16678
16679/*
16680 * Read EEPROM configuration into the specified buffer.
16681 *
16682 * Return a checksum based on the EEPROM configuration read.
16683 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016684static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016685AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016686{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016687 ushort wval, chksum;
16688 ushort *wbuf;
16689 int eep_addr;
16690 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016692 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16693 wbuf = (ushort *)cfg_buf;
16694 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016695
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016696 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16697 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16698 wval = AdvReadEEPWord(iop_base, eep_addr);
16699 chksum += wval; /* Checksum is calculated from word values. */
16700 if (*charfields++) {
16701 *wbuf = le16_to_cpu(wval);
16702 } else {
16703 *wbuf = wval;
16704 }
16705 }
16706 /* Read checksum word. */
16707 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16708 wbuf++;
16709 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016710
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016711 /* Read rest of EEPROM not covered by the checksum. */
16712 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16713 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16714 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16715 if (*charfields++) {
16716 *wbuf = le16_to_cpu(*wbuf);
16717 }
16718 }
16719 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016720}
16721
16722/*
16723 * Read the EEPROM from specified location
16724 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016725static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016726{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016727 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16728 ASC_EEP_CMD_READ | eep_word_addr);
16729 AdvWaitEEPCmd(iop_base);
16730 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016731}
16732
16733/*
16734 * Wait for EEPROM command to complete
16735 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016736static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016737{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016738 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016739
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016740 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16741 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16742 ASC_EEP_CMD_DONE) {
16743 break;
16744 }
16745 DvcSleepMilliSecond(1);
16746 }
16747 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16748 0) {
16749 ASC_ASSERT(0);
16750 }
16751 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016752}
16753
16754/*
16755 * Write the EEPROM from 'cfg_buf'.
16756 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016757void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016758AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16759{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016760 ushort *wbuf;
16761 ushort addr, chksum;
16762 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016763
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016764 wbuf = (ushort *)cfg_buf;
16765 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16766 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016767
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016768 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16769 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016770
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016771 /*
16772 * Write EEPROM from word 0 to word 20.
16773 */
16774 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16775 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16776 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016777
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016778 if (*charfields++) {
16779 word = cpu_to_le16(*wbuf);
16780 } else {
16781 word = *wbuf;
16782 }
16783 chksum += *wbuf; /* Checksum is calculated from word values. */
16784 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16785 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16786 ASC_EEP_CMD_WRITE | addr);
16787 AdvWaitEEPCmd(iop_base);
16788 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016790
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016791 /*
16792 * Write EEPROM checksum at word 21.
16793 */
16794 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16795 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16796 AdvWaitEEPCmd(iop_base);
16797 wbuf++;
16798 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016799
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016800 /*
16801 * Write EEPROM OEM name at words 22 to 29.
16802 */
16803 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16804 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16805 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016807 if (*charfields++) {
16808 word = cpu_to_le16(*wbuf);
16809 } else {
16810 word = *wbuf;
16811 }
16812 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16813 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16814 ASC_EEP_CMD_WRITE | addr);
16815 AdvWaitEEPCmd(iop_base);
16816 }
16817 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16818 AdvWaitEEPCmd(iop_base);
16819 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016820}
16821
16822/*
16823 * Write the EEPROM from 'cfg_buf'.
16824 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016825void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016826AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016827{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016828 ushort *wbuf;
16829 ushort *charfields;
16830 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016831
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016832 wbuf = (ushort *)cfg_buf;
16833 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16834 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016835
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016836 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16837 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016838
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016839 /*
16840 * Write EEPROM from word 0 to word 20.
16841 */
16842 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16843 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16844 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016845
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016846 if (*charfields++) {
16847 word = cpu_to_le16(*wbuf);
16848 } else {
16849 word = *wbuf;
16850 }
16851 chksum += *wbuf; /* Checksum is calculated from word values. */
16852 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16853 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16854 ASC_EEP_CMD_WRITE | addr);
16855 AdvWaitEEPCmd(iop_base);
16856 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016858
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016859 /*
16860 * Write EEPROM checksum at word 21.
16861 */
16862 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16863 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16864 AdvWaitEEPCmd(iop_base);
16865 wbuf++;
16866 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016867
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016868 /*
16869 * Write EEPROM OEM name at words 22 to 29.
16870 */
16871 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16872 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16873 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016874
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016875 if (*charfields++) {
16876 word = cpu_to_le16(*wbuf);
16877 } else {
16878 word = *wbuf;
16879 }
16880 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16881 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16882 ASC_EEP_CMD_WRITE | addr);
16883 AdvWaitEEPCmd(iop_base);
16884 }
16885 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16886 AdvWaitEEPCmd(iop_base);
16887 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016888}
16889
16890/*
16891 * Write the EEPROM from 'cfg_buf'.
16892 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016893void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016894AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016895{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016896 ushort *wbuf;
16897 ushort *charfields;
16898 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016899
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016900 wbuf = (ushort *)cfg_buf;
16901 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16902 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016903
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016904 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16905 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016906
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016907 /*
16908 * Write EEPROM from word 0 to word 20.
16909 */
16910 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16911 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16912 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016913
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016914 if (*charfields++) {
16915 word = cpu_to_le16(*wbuf);
16916 } else {
16917 word = *wbuf;
16918 }
16919 chksum += *wbuf; /* Checksum is calculated from word values. */
16920 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16921 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16922 ASC_EEP_CMD_WRITE | addr);
16923 AdvWaitEEPCmd(iop_base);
16924 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016926
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016927 /*
16928 * Write EEPROM checksum at word 21.
16929 */
16930 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16931 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16932 AdvWaitEEPCmd(iop_base);
16933 wbuf++;
16934 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016935
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016936 /*
16937 * Write EEPROM OEM name at words 22 to 29.
16938 */
16939 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16940 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16941 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016942
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016943 if (*charfields++) {
16944 word = cpu_to_le16(*wbuf);
16945 } else {
16946 word = *wbuf;
16947 }
16948 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16949 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16950 ASC_EEP_CMD_WRITE | addr);
16951 AdvWaitEEPCmd(iop_base);
16952 }
16953 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16954 AdvWaitEEPCmd(iop_base);
16955 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016956}
16957
16958/* a_advlib.c */
16959/*
16960 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
16961 *
16962 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
16963 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
16964 * RISC to notify it a new command is ready to be executed.
16965 *
16966 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
16967 * set to SCSI_MAX_RETRY.
16968 *
16969 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
16970 * for DMA addresses or math operations are byte swapped to little-endian
16971 * order.
16972 *
16973 * Return:
16974 * ADV_SUCCESS(1) - The request was successfully queued.
16975 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
16976 * request completes.
16977 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
16978 * host IC error.
16979 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016980static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016981{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016982 ulong last_int_level;
16983 AdvPortAddr iop_base;
16984 ADV_DCNT req_size;
16985 ADV_PADDR req_paddr;
16986 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016987
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016988 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016989
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016990 /*
16991 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
16992 */
16993 if (scsiq->target_id > ADV_MAX_TID) {
16994 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
16995 scsiq->done_status = QD_WITH_ERROR;
16996 return ADV_ERROR;
16997 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016998
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016999 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017000
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017001 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017002
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017003 /*
17004 * Allocate a carrier ensuring at least one carrier always
17005 * remains on the freelist and initialize fields.
17006 */
17007 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
17008 DvcLeaveCritical(last_int_level);
17009 return ADV_BUSY;
17010 }
17011 asc_dvc->carr_freelist = (ADV_CARR_T *)
17012 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
17013 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017014
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017015 /*
17016 * Set the carrier to be a stopper by setting 'next_vpa'
17017 * to the stopper value. The current stopper will be changed
17018 * below to point to the new stopper.
17019 */
17020 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017021
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017022 /*
17023 * Clear the ADV_SCSI_REQ_Q done flag.
17024 */
17025 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017026
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017027 req_size = sizeof(ADV_SCSI_REQ_Q);
17028 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
17029 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017031 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
17032 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017033
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017034 /* Wait for assertion before making little-endian */
17035 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017036
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017037 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
17038 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
17039 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017040
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017041 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
17042 /*
17043 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
17044 * order during initialization.
17045 */
17046 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017047
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017048 /*
17049 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
17050 * the microcode. The newly allocated stopper will become the new
17051 * stopper.
17052 */
17053 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017054
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017055 /*
17056 * Set the 'next_vpa' pointer for the old stopper to be the
17057 * physical address of the new stopper. The RISC can only
17058 * follow physical addresses.
17059 */
17060 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017061
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017062 /*
17063 * Set the host adapter stopper pointer to point to the new carrier.
17064 */
17065 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017066
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017067 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
17068 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17069 /*
17070 * Tickle the RISC to tell it to read its Command Queue Head pointer.
17071 */
17072 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
17073 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17074 /*
17075 * Clear the tickle value. In the ASC-3550 the RISC flag
17076 * command 'clr_tickle_a' does not work unless the host
17077 * value is cleared.
17078 */
17079 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
17080 ADV_TICKLE_NOP);
17081 }
17082 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17083 /*
17084 * Notify the RISC a carrier is ready by writing the physical
17085 * address of the new carrier stopper to the COMMA register.
17086 */
17087 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
17088 le32_to_cpu(new_carrp->carr_pa));
17089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017090
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017091 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017092
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017093 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017094}
17095
17096/*
17097 * Reset SCSI Bus and purge all outstanding requests.
17098 *
17099 * Return Value:
17100 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
17101 * ADV_FALSE(0) - Microcode command failed.
17102 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
17103 * may be hung which requires driver recovery.
17104 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017105static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017106{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017107 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017108
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017109 /*
17110 * Send the SCSI Bus Reset idle start idle command which asserts
17111 * the SCSI Bus Reset signal.
17112 */
17113 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
17114 if (status != ADV_TRUE) {
17115 return status;
17116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017117
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017118 /*
17119 * Delay for the specified SCSI Bus Reset hold time.
17120 *
17121 * The hold time delay is done on the host because the RISC has no
17122 * microsecond accurate timer.
17123 */
17124 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017125
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017126 /*
17127 * Send the SCSI Bus Reset end idle command which de-asserts
17128 * the SCSI Bus Reset signal and purges any pending requests.
17129 */
17130 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
17131 if (status != ADV_TRUE) {
17132 return status;
17133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017135 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017136
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017137 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017138}
17139
17140/*
17141 * Reset chip and SCSI Bus.
17142 *
17143 * Return Value:
17144 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
17145 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
17146 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017147static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017148{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017149 int status;
17150 ushort wdtr_able, sdtr_able, tagqng_able;
17151 ushort ppr_able = 0;
17152 uchar tid, max_cmd[ADV_MAX_TID + 1];
17153 AdvPortAddr iop_base;
17154 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017155
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017156 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017157
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017158 /*
17159 * Save current per TID negotiated values.
17160 */
17161 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
17162 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
17163 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17164 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
17165 }
17166 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
17167 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
17168 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
17169 max_cmd[tid]);
17170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017171
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017172 /*
17173 * Force the AdvInitAsc3550/38C0800Driver() function to
17174 * perform a SCSI Bus Reset by clearing the BIOS signature word.
17175 * The initialization functions assumes a SCSI Bus Reset is not
17176 * needed if the BIOS signature word is present.
17177 */
17178 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
17179 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017180
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017181 /*
17182 * Stop chip and reset it.
17183 */
17184 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
17185 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
17186 DvcSleepMilliSecond(100);
17187 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
17188 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017189
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017190 /*
17191 * Reset Adv Library error code, if any, and try
17192 * re-initializing the chip.
17193 */
17194 asc_dvc->err_code = 0;
17195 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17196 status = AdvInitAsc38C1600Driver(asc_dvc);
17197 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17198 status = AdvInitAsc38C0800Driver(asc_dvc);
17199 } else {
17200 status = AdvInitAsc3550Driver(asc_dvc);
17201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017202
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017203 /* Translate initialization return value to status value. */
17204 if (status == 0) {
17205 status = ADV_TRUE;
17206 } else {
17207 status = ADV_FALSE;
17208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017209
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017210 /*
17211 * Restore the BIOS signature word.
17212 */
17213 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017214
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017215 /*
17216 * Restore per TID negotiated values.
17217 */
17218 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
17219 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
17220 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
17221 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
17222 }
17223 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
17224 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
17225 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
17226 max_cmd[tid]);
17227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017228
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017229 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017230}
17231
17232/*
17233 * Adv Library Interrupt Service Routine
17234 *
17235 * This function is called by a driver's interrupt service routine.
17236 * The function disables and re-enables interrupts.
17237 *
17238 * When a microcode idle command is completed, the ADV_DVC_VAR
17239 * 'idle_cmd_done' field is set to ADV_TRUE.
17240 *
17241 * Note: AdvISR() can be called when interrupts are disabled or even
17242 * when there is no hardware interrupt condition present. It will
17243 * always check for completed idle commands and microcode requests.
17244 * This is an important feature that shouldn't be changed because it
17245 * allows commands to be completed from polling mode loops.
17246 *
17247 * Return:
17248 * ADV_TRUE(1) - interrupt was pending
17249 * ADV_FALSE(0) - no interrupt was pending
17250 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017251static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017252{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017253 AdvPortAddr iop_base;
17254 uchar int_stat;
17255 ushort target_bit;
17256 ADV_CARR_T *free_carrp;
17257 ADV_VADDR irq_next_vpa;
17258 int flags;
17259 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017260
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017261 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017263 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017264
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017265 /* Reading the register clears the interrupt. */
17266 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017267
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017268 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
17269 ADV_INTR_STATUS_INTRC)) == 0) {
17270 DvcLeaveCritical(flags);
17271 return ADV_FALSE;
17272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017273
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017274 /*
17275 * Notify the driver of an asynchronous microcode condition by
17276 * calling the ADV_DVC_VAR.async_callback function. The function
17277 * is passed the microcode ASC_MC_INTRB_CODE byte value.
17278 */
17279 if (int_stat & ADV_INTR_STATUS_INTRB) {
17280 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017281
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017282 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017283
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017284 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
17285 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
17286 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
17287 asc_dvc->carr_pending_cnt != 0) {
17288 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
17289 ADV_TICKLE_A);
17290 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17291 AdvWriteByteRegister(iop_base,
17292 IOPB_TICKLE,
17293 ADV_TICKLE_NOP);
17294 }
17295 }
17296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017297
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017298 if (asc_dvc->async_callback != 0) {
17299 (*asc_dvc->async_callback) (asc_dvc, intrb_code);
17300 }
17301 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017302
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017303 /*
17304 * Check if the IRQ stopper carrier contains a completed request.
17305 */
17306 while (((irq_next_vpa =
17307 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
17308 /*
17309 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
17310 * The RISC will have set 'areq_vpa' to a virtual address.
17311 *
17312 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
17313 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
17314 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
17315 * in AdvExeScsiQueue().
17316 */
17317 scsiq = (ADV_SCSI_REQ_Q *)
17318 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017319
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017320 /*
17321 * Request finished with good status and the queue was not
17322 * DMAed to host memory by the firmware. Set all status fields
17323 * to indicate good status.
17324 */
17325 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
17326 scsiq->done_status = QD_NO_ERROR;
17327 scsiq->host_status = scsiq->scsi_status = 0;
17328 scsiq->data_cnt = 0L;
17329 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017330
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017331 /*
17332 * Advance the stopper pointer to the next carrier
17333 * ignoring the lower four bits. Free the previous
17334 * stopper carrier.
17335 */
17336 free_carrp = asc_dvc->irq_sp;
17337 asc_dvc->irq_sp = (ADV_CARR_T *)
17338 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070017339
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017340 free_carrp->next_vpa =
17341 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
17342 asc_dvc->carr_freelist = free_carrp;
17343 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017344
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017345 ASC_ASSERT(scsiq != NULL);
17346 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017347
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017348 /*
17349 * Clear request microcode control flag.
17350 */
17351 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017352
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017353 /*
17354 * If the command that completed was a SCSI INQUIRY and
17355 * LUN 0 was sent the command, then process the INQUIRY
17356 * command information for the device.
17357 *
17358 * Note: If data returned were either VPD or CmdDt data,
17359 * don't process the INQUIRY command information for
17360 * the device, otherwise may erroneously set *_able bits.
17361 */
17362 if (scsiq->done_status == QD_NO_ERROR &&
17363 scsiq->cdb[0] == INQUIRY &&
17364 scsiq->target_lun == 0 &&
17365 (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
17366 == ADV_INQ_RTN_STD_INQUIRY_DATA) {
17367 AdvInquiryHandling(asc_dvc, scsiq);
17368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017369
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017370 /*
17371 * Notify the driver of the completed request by passing
17372 * the ADV_SCSI_REQ_Q pointer to its callback function.
17373 */
17374 scsiq->a_flag |= ADV_SCSIQ_DONE;
17375 (*asc_dvc->isr_callback) (asc_dvc, scsiq);
17376 /*
17377 * Note: After the driver callback function is called, 'scsiq'
17378 * can no longer be referenced.
17379 *
17380 * Fall through and continue processing other completed
17381 * requests...
17382 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017383
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017384 /*
17385 * Disable interrupts again in case the driver inadvertently
17386 * enabled interrupts in its callback function.
17387 *
17388 * The DvcEnterCritical() return value is ignored, because
17389 * the 'flags' saved when AdvISR() was first entered will be
17390 * used to restore the interrupt flag on exit.
17391 */
17392 (void)DvcEnterCritical();
17393 }
17394 DvcLeaveCritical(flags);
17395 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017396}
17397
17398/*
17399 * Send an idle command to the chip and wait for completion.
17400 *
17401 * Command completion is polled for once per microsecond.
17402 *
17403 * The function can be called from anywhere including an interrupt handler.
17404 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
17405 * functions to prevent reentrancy.
17406 *
17407 * Return Values:
17408 * ADV_TRUE - command completed successfully
17409 * ADV_FALSE - command failed
17410 * ADV_ERROR - command timed out
17411 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017412static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070017413AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017414 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017415{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017416 ulong last_int_level;
17417 int result;
17418 ADV_DCNT i, j;
17419 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017420
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017421 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017422
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017423 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017424
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017425 /*
17426 * Clear the idle command status which is set by the microcode
17427 * to a non-zero value to indicate when the command is completed.
17428 * The non-zero result is one of the IDLE_CMD_STATUS_* values
17429 * defined in a_advlib.h.
17430 */
17431 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017432
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017433 /*
17434 * Write the idle command value after the idle command parameter
17435 * has been written to avoid a race condition. If the order is not
17436 * followed, the microcode may process the idle command before the
17437 * parameters have been written to LRAM.
17438 */
17439 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
17440 cpu_to_le32(idle_cmd_parameter));
17441 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017442
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017443 /*
17444 * Tickle the RISC to tell it to process the idle command.
17445 */
17446 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
17447 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17448 /*
17449 * Clear the tickle value. In the ASC-3550 the RISC flag
17450 * command 'clr_tickle_b' does not work unless the host
17451 * value is cleared.
17452 */
17453 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
17454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017455
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017456 /* Wait for up to 100 millisecond for the idle command to timeout. */
17457 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
17458 /* Poll once each microsecond for command completion. */
17459 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
17460 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
17461 result);
17462 if (result != 0) {
17463 DvcLeaveCritical(last_int_level);
17464 return result;
17465 }
17466 DvcDelayMicroSecond(asc_dvc, (ushort)1);
17467 }
17468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017469
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017470 ASC_ASSERT(0); /* The idle command should never timeout. */
17471 DvcLeaveCritical(last_int_level);
17472 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017473}
17474
17475/*
17476 * Inquiry Information Byte 7 Handling
17477 *
17478 * Handle SCSI Inquiry Command information for a device by setting
17479 * microcode operating variables that affect WDTR, SDTR, and Tag
17480 * Queuing.
17481 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017482static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017483{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017484 AdvPortAddr iop_base;
17485 uchar tid;
17486 ADV_SCSI_INQUIRY *inq;
17487 ushort tidmask;
17488 ushort cfg_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017489
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017490 /*
17491 * AdvInquiryHandling() requires up to INQUIRY information Byte 7
17492 * to be available.
17493 *
17494 * If less than 8 bytes of INQUIRY information were requested or less
17495 * than 8 bytes were transferred, then return. cdb[4] is the request
17496 * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
17497 * microcode to the transfer residual count.
17498 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017499
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017500 if (scsiq->cdb[4] < 8 ||
17501 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) {
17502 return;
17503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017504
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017505 iop_base = asc_dvc->iop_base;
17506 tid = scsiq->target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017507
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017508 inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017509
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017510 /*
17511 * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
17512 */
17513 if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) {
17514 return;
17515 } else {
17516 /*
17517 * INQUIRY Byte 7 Handling
17518 *
17519 * Use a device's INQUIRY byte 7 to determine whether it
17520 * supports WDTR, SDTR, and Tag Queuing. If the feature
17521 * is enabled in the EEPROM and the device supports the
17522 * feature, then enable it in the microcode.
17523 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017524
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017525 tidmask = ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017526
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017527 /*
17528 * Wide Transfers
17529 *
17530 * If the EEPROM enabled WDTR for the device and the device
17531 * supports wide bus (16 bit) transfers, then turn on the
17532 * device's 'wdtr_able' bit and write the new value to the
17533 * microcode.
17534 */
17535 if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) {
17536 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
17537 if ((cfg_word & tidmask) == 0) {
17538 cfg_word |= tidmask;
17539 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
17540 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017541
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017542 /*
17543 * Clear the microcode "SDTR negotiation" and "WDTR
17544 * negotiation" done indicators for the target to cause
17545 * it to negotiate with the new setting set above.
17546 * WDTR when accepted causes the target to enter
17547 * asynchronous mode, so SDTR must be negotiated.
17548 */
17549 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17550 cfg_word);
17551 cfg_word &= ~tidmask;
17552 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17553 cfg_word);
17554 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE,
17555 cfg_word);
17556 cfg_word &= ~tidmask;
17557 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE,
17558 cfg_word);
17559 }
17560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017561
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017562 /*
17563 * Synchronous Transfers
17564 *
17565 * If the EEPROM enabled SDTR for the device and the device
17566 * supports synchronous transfers, then turn on the device's
17567 * 'sdtr_able' bit. Write the new value to the microcode.
17568 */
17569 if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) {
17570 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
17571 if ((cfg_word & tidmask) == 0) {
17572 cfg_word |= tidmask;
17573 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
17574 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017575
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017576 /*
17577 * Clear the microcode "SDTR negotiation" done indicator
17578 * for the target to cause it to negotiate with the new
17579 * setting set above.
17580 */
17581 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17582 cfg_word);
17583 cfg_word &= ~tidmask;
17584 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17585 cfg_word);
17586 }
17587 }
17588 /*
17589 * If the Inquiry data included enough space for the SPI-3
17590 * Clocking field, then check if DT mode is supported.
17591 */
17592 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
17593 (scsiq->cdb[4] >= 57 ||
17594 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) {
17595 /*
17596 * PPR (Parallel Protocol Request) Capable
17597 *
17598 * If the device supports DT mode, then it must be PPR capable.
17599 * The PPR message will be used in place of the SDTR and WDTR
17600 * messages to negotiate synchronous speed and offset, transfer
17601 * width, and protocol options.
17602 */
17603 if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) {
17604 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE,
17605 asc_dvc->ppr_able);
17606 asc_dvc->ppr_able |= tidmask;
17607 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE,
17608 asc_dvc->ppr_able);
17609 }
17610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017611
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017612 /*
17613 * If the EEPROM enabled Tag Queuing for the device and the
17614 * device supports Tag Queueing, then turn on the device's
17615 * 'tagqng_enable' bit in the microcode and set the microcode
17616 * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
17617 * value.
17618 *
17619 * Tag Queuing is disabled for the BIOS which runs in polled
17620 * mode and would see no benefit from Tag Queuing. Also by
17621 * disabling Tag Queuing in the BIOS devices with Tag Queuing
17622 * bugs will at least work with the BIOS.
17623 */
17624 if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) {
17625 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
17626 cfg_word |= tidmask;
17627 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
17628 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017630 AdvWriteByteLram(iop_base,
17631 ASC_MC_NUMBER_OF_MAX_CMD + tid,
17632 asc_dvc->max_dvc_qng);
17633 }
17634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017635}
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017636
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017637static int __devinit
17638advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
17639{
17640 int req_cnt = 0;
17641 adv_req_t *reqp = NULL;
17642 int sg_cnt = 0;
17643 adv_sgblk_t *sgp;
17644 int warn_code, err_code;
17645
17646 /*
17647 * Allocate buffer carrier structures. The total size
17648 * is about 4 KB, so allocate all at once.
17649 */
17650 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
17651 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
17652
17653 if (!boardp->carrp)
17654 goto kmalloc_failed;
17655
17656 /*
17657 * Allocate up to 'max_host_qng' request structures for the Wide
17658 * board. The total size is about 16 KB, so allocate all at once.
17659 * If the allocation fails decrement and try again.
17660 */
17661 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
17662 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
17663
17664 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
17665 "bytes %lu\n", reqp, req_cnt,
17666 (ulong)sizeof(adv_req_t) * req_cnt);
17667
17668 if (reqp)
17669 break;
17670 }
17671
17672 if (!reqp)
17673 goto kmalloc_failed;
17674
17675 boardp->orig_reqp = reqp;
17676
17677 /*
17678 * Allocate up to ADV_TOT_SG_BLOCK request structures for
17679 * the Wide board. Each structure is about 136 bytes.
17680 */
17681 boardp->adv_sgblkp = NULL;
17682 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
17683 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
17684
17685 if (!sgp)
17686 break;
17687
17688 sgp->next_sgblkp = boardp->adv_sgblkp;
17689 boardp->adv_sgblkp = sgp;
17690
17691 }
17692
17693 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
17694 sg_cnt, sizeof(adv_sgblk_t),
17695 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
17696
17697 if (!boardp->adv_sgblkp)
17698 goto kmalloc_failed;
17699
17700 adv_dvc_varp->carrier_buf = boardp->carrp;
17701
17702 /*
17703 * Point 'adv_reqp' to the request structures and
17704 * link them together.
17705 */
17706 req_cnt--;
17707 reqp[req_cnt].next_reqp = NULL;
17708 for (; req_cnt > 0; req_cnt--) {
17709 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
17710 }
17711 boardp->adv_reqp = &reqp[0];
17712
17713 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17714 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
17715 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
17716 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17717 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
17718 "\n");
17719 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
17720 } else {
17721 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
17722 "\n");
17723 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
17724 }
17725 err_code = adv_dvc_varp->err_code;
17726
17727 if (warn_code || err_code) {
17728 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
17729 " error 0x%x\n", boardp->id, warn_code, err_code);
17730 }
17731
17732 goto exit;
17733
17734 kmalloc_failed:
17735 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
17736 "failed\n", boardp->id);
17737 err_code = ADV_ERROR;
17738 exit:
17739 return err_code;
17740}
17741
17742static void advansys_wide_free_mem(asc_board_t *boardp)
17743{
17744 kfree(boardp->carrp);
17745 boardp->carrp = NULL;
17746 kfree(boardp->orig_reqp);
17747 boardp->orig_reqp = boardp->adv_reqp = NULL;
17748 while (boardp->adv_sgblkp) {
17749 adv_sgblk_t *sgp = boardp->adv_sgblkp;
17750 boardp->adv_sgblkp = sgp->next_sgblkp;
17751 kfree(sgp);
17752 }
17753}
17754
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017755static struct Scsi_Host *__devinit
17756advansys_board_found(int iop, struct device *dev, int bus_type)
17757{
17758 struct Scsi_Host *shost;
17759 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
17760 asc_board_t *boardp;
17761 ASC_DVC_VAR *asc_dvc_varp = NULL;
17762 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017763 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017764 int iolen = 0;
17765 ADV_PADDR pci_memory_address;
17766 int warn_code, err_code;
17767 int ret;
17768
17769 /*
17770 * Adapter found.
17771 *
17772 * Register the adapter, get its configuration, and
17773 * initialize it.
17774 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017775 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
17776 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017777
17778 if (!shost)
17779 return NULL;
17780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017781 /* Initialize private per board data */
17782 boardp = ASC_BOARDP(shost);
17783 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017784 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017785
17786 /* Initialize spinlock. */
17787 spin_lock_init(&boardp->lock);
17788
17789 /*
17790 * Handle both narrow and wide boards.
17791 *
17792 * If a Wide board was detected, set the board structure
17793 * wide board flag. Set-up the board structure based on
17794 * the board type.
17795 */
17796#ifdef CONFIG_PCI
17797 if (bus_type == ASC_IS_PCI &&
17798 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17799 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17800 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17801 boardp->flags |= ASC_IS_WIDE_BOARD;
17802 }
17803#endif /* CONFIG_PCI */
17804
17805 if (ASC_NARROW_BOARD(boardp)) {
17806 ASC_DBG(1, "advansys_board_found: narrow board\n");
17807 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17808 asc_dvc_varp->bus_type = bus_type;
17809 asc_dvc_varp->drv_ptr = boardp;
17810 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17811 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17812 asc_dvc_varp->iop_base = iop;
17813 asc_dvc_varp->isr_callback = asc_isr_callback;
17814 } else {
17815 ASC_DBG(1, "advansys_board_found: wide board\n");
17816 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17817 adv_dvc_varp->drv_ptr = boardp;
17818 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
17819 adv_dvc_varp->isr_callback = adv_isr_callback;
17820 adv_dvc_varp->async_callback = adv_async_callback;
17821#ifdef CONFIG_PCI
17822 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17823 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17824 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17825 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17826 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17827 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17828 } else {
17829 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17830 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17831 }
17832#endif /* CONFIG_PCI */
17833
17834 /*
17835 * Map the board's registers into virtual memory for
17836 * PCI slave access. Only memory accesses are used to
17837 * access the board's registers.
17838 *
17839 * Note: The PCI register base address is not always
17840 * page aligned, but the address passed to ioremap()
17841 * must be page aligned. It is guaranteed that the
17842 * PCI register base address will not cross a page
17843 * boundary.
17844 */
17845 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17846 iolen = ADV_3550_IOLEN;
17847 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17848 iolen = ADV_38C0800_IOLEN;
17849 } else {
17850 iolen = ADV_38C1600_IOLEN;
17851 }
17852#ifdef CONFIG_PCI
17853 pci_memory_address = pci_resource_start(pdev, 1);
17854 ASC_DBG1(1,
17855 "advansys_board_found: pci_memory_address: 0x%lx\n",
17856 (ulong)pci_memory_address);
17857 if ((boardp->ioremap_addr =
17858 ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
17859 ASC_PRINT3
17860 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
17861 boardp->id, pci_memory_address, iolen);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017862 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017863 }
17864 ASC_DBG1(1,
17865 "advansys_board_found: ioremap_addr: 0x%lx\n",
17866 (ulong)boardp->ioremap_addr);
17867 adv_dvc_varp->iop_base = (AdvPortAddr)
17868 (boardp->ioremap_addr +
17869 (pci_memory_address - (pci_memory_address & PAGE_MASK)));
17870 ASC_DBG1(1,
17871 "advansys_board_found: iop_base: 0x%lx\n",
17872 adv_dvc_varp->iop_base);
17873#endif /* CONFIG_PCI */
17874
17875 /*
17876 * Even though it isn't used to access wide boards, other
17877 * than for the debug line below, save I/O Port address so
17878 * that it can be reported.
17879 */
17880 boardp->ioport = iop;
17881
17882 ASC_DBG2(1,
17883 "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
17884 (ushort)inp(iop + 1), (ushort)inpw(iop));
17885 }
17886
17887#ifdef CONFIG_PROC_FS
17888 /*
17889 * Allocate buffer for printing information from
17890 * /proc/scsi/advansys/[0...].
17891 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017892 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
17893 if (!boardp->prtbuf) {
17894 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
17895 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
17896 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017897 }
17898#endif /* CONFIG_PROC_FS */
17899
17900 if (ASC_NARROW_BOARD(boardp)) {
17901 asc_dvc_varp->cfg->dev = dev;
17902 /*
17903 * Set the board bus type and PCI IRQ before
17904 * calling AscInitGetConfig().
17905 */
17906 switch (asc_dvc_varp->bus_type) {
17907#ifdef CONFIG_ISA
17908 case ASC_IS_ISA:
17909 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017910 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017911 break;
17912 case ASC_IS_VL:
17913 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017914 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017915 break;
17916 case ASC_IS_EISA:
17917 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017918 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017919 break;
17920#endif /* CONFIG_ISA */
17921#ifdef CONFIG_PCI
17922 case ASC_IS_PCI:
17923 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
17924 asc_dvc_varp->cfg->pci_slot_info =
17925 ASC_PCI_MKID(pdev->bus->number,
17926 PCI_SLOT(pdev->devfn),
17927 PCI_FUNC(pdev->devfn));
17928 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017929 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017930 break;
17931#endif /* CONFIG_PCI */
17932 default:
17933 ASC_PRINT2
17934 ("advansys_board_found: board %d: unknown adapter type: %d\n",
17935 boardp->id, asc_dvc_varp->bus_type);
17936 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017937 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017938 break;
17939 }
17940 } else {
17941 adv_dvc_varp->cfg->dev = dev;
17942 /*
17943 * For Wide boards set PCI information before calling
17944 * AdvInitGetConfig().
17945 */
17946#ifdef CONFIG_PCI
17947 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
17948 adv_dvc_varp->cfg->pci_slot_info =
17949 ASC_PCI_MKID(pdev->bus->number,
17950 PCI_SLOT(pdev->devfn),
17951 PCI_FUNC(pdev->devfn));
17952 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017953 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017954#endif /* CONFIG_PCI */
17955 }
17956
17957 /*
17958 * Read the board configuration.
17959 */
17960 if (ASC_NARROW_BOARD(boardp)) {
17961 /*
17962 * NOTE: AscInitGetConfig() may change the board's
17963 * bus_type value. The bus_type value should no
17964 * longer be used. If the bus_type field must be
17965 * referenced only use the bit-wise AND operator "&".
17966 */
17967 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
17968 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
17969 case 0: /* No error */
17970 break;
17971 case ASC_WARN_IO_PORT_ROTATE:
17972 ASC_PRINT1
17973 ("AscInitGetConfig: board %d: I/O port address modified\n",
17974 boardp->id);
17975 break;
17976 case ASC_WARN_AUTO_CONFIG:
17977 ASC_PRINT1
17978 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
17979 boardp->id);
17980 break;
17981 case ASC_WARN_EEPROM_CHKSUM:
17982 ASC_PRINT1
17983 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
17984 boardp->id);
17985 break;
17986 case ASC_WARN_IRQ_MODIFIED:
17987 ASC_PRINT1
17988 ("AscInitGetConfig: board %d: IRQ modified\n",
17989 boardp->id);
17990 break;
17991 case ASC_WARN_CMD_QNG_CONFLICT:
17992 ASC_PRINT1
17993 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
17994 boardp->id);
17995 break;
17996 default:
17997 ASC_PRINT2
17998 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
17999 boardp->id, ret);
18000 break;
18001 }
18002 if ((err_code = asc_dvc_varp->err_code) != 0) {
18003 ASC_PRINT3
18004 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
18005 boardp->id,
18006 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
18007 }
18008 } else {
18009 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
18010 if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
18011 ASC_PRINT2
18012 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
18013 boardp->id, ret);
18014 }
18015 if ((err_code = adv_dvc_varp->err_code) != 0) {
18016 ASC_PRINT2
18017 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
18018 boardp->id, adv_dvc_varp->err_code);
18019 }
18020 }
18021
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018022 if (err_code != 0)
18023 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018024
18025 /*
18026 * Save the EEPROM configuration so that it can be displayed
18027 * from /proc/scsi/advansys/[0...].
18028 */
18029 if (ASC_NARROW_BOARD(boardp)) {
18030
18031 ASCEEP_CONFIG *ep;
18032
18033 /*
18034 * Set the adapter's target id bit in the 'init_tidmask' field.
18035 */
18036 boardp->init_tidmask |=
18037 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
18038
18039 /*
18040 * Save EEPROM settings for the board.
18041 */
18042 ep = &boardp->eep_config.asc_eep;
18043
18044 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
18045 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
18046 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
18047 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
18048 ep->start_motor = asc_dvc_varp->start_motor;
18049 ep->cntl = asc_dvc_varp->dvc_cntl;
18050 ep->no_scam = asc_dvc_varp->no_scam;
18051 ep->max_total_qng = asc_dvc_varp->max_total_qng;
18052 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
18053 /* 'max_tag_qng' is set to the same value for every device. */
18054 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
18055 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
18056 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
18057 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
18058 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
18059 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
18060 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
18061
18062 /*
18063 * Modify board configuration.
18064 */
18065 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
18066 switch (ret = AscInitSetConfig(asc_dvc_varp)) {
18067 case 0: /* No error. */
18068 break;
18069 case ASC_WARN_IO_PORT_ROTATE:
18070 ASC_PRINT1
18071 ("AscInitSetConfig: board %d: I/O port address modified\n",
18072 boardp->id);
18073 break;
18074 case ASC_WARN_AUTO_CONFIG:
18075 ASC_PRINT1
18076 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
18077 boardp->id);
18078 break;
18079 case ASC_WARN_EEPROM_CHKSUM:
18080 ASC_PRINT1
18081 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
18082 boardp->id);
18083 break;
18084 case ASC_WARN_IRQ_MODIFIED:
18085 ASC_PRINT1
18086 ("AscInitSetConfig: board %d: IRQ modified\n",
18087 boardp->id);
18088 break;
18089 case ASC_WARN_CMD_QNG_CONFLICT:
18090 ASC_PRINT1
18091 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
18092 boardp->id);
18093 break;
18094 default:
18095 ASC_PRINT2
18096 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
18097 boardp->id, ret);
18098 break;
18099 }
18100 if (asc_dvc_varp->err_code != 0) {
18101 ASC_PRINT3
18102 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
18103 boardp->id,
18104 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018105 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018106 }
18107
18108 /*
18109 * Finish initializing the 'Scsi_Host' structure.
18110 */
18111 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
18112 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
18113 shost->irq = asc_dvc_varp->irq_no;
18114 }
18115 } else {
18116 ADVEEP_3550_CONFIG *ep_3550;
18117 ADVEEP_38C0800_CONFIG *ep_38C0800;
18118 ADVEEP_38C1600_CONFIG *ep_38C1600;
18119
18120 /*
18121 * Save Wide EEP Configuration Information.
18122 */
18123 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
18124 ep_3550 = &boardp->eep_config.adv_3550_eep;
18125
18126 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
18127 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
18128 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18129 ep_3550->termination = adv_dvc_varp->cfg->termination;
18130 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
18131 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
18132 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
18133 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
18134 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
18135 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
18136 ep_3550->start_motor = adv_dvc_varp->start_motor;
18137 ep_3550->scsi_reset_delay =
18138 adv_dvc_varp->scsi_reset_wait;
18139 ep_3550->serial_number_word1 =
18140 adv_dvc_varp->cfg->serial1;
18141 ep_3550->serial_number_word2 =
18142 adv_dvc_varp->cfg->serial2;
18143 ep_3550->serial_number_word3 =
18144 adv_dvc_varp->cfg->serial3;
18145 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
18146 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
18147
18148 ep_38C0800->adapter_scsi_id =
18149 adv_dvc_varp->chip_scsi_id;
18150 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
18151 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18152 ep_38C0800->termination_lvd =
18153 adv_dvc_varp->cfg->termination;
18154 ep_38C0800->disc_enable =
18155 adv_dvc_varp->cfg->disc_enable;
18156 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
18157 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
18158 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
18159 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
18160 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
18161 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
18162 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
18163 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
18164 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
18165 ep_38C0800->scsi_reset_delay =
18166 adv_dvc_varp->scsi_reset_wait;
18167 ep_38C0800->serial_number_word1 =
18168 adv_dvc_varp->cfg->serial1;
18169 ep_38C0800->serial_number_word2 =
18170 adv_dvc_varp->cfg->serial2;
18171 ep_38C0800->serial_number_word3 =
18172 adv_dvc_varp->cfg->serial3;
18173 } else {
18174 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
18175
18176 ep_38C1600->adapter_scsi_id =
18177 adv_dvc_varp->chip_scsi_id;
18178 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
18179 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
18180 ep_38C1600->termination_lvd =
18181 adv_dvc_varp->cfg->termination;
18182 ep_38C1600->disc_enable =
18183 adv_dvc_varp->cfg->disc_enable;
18184 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
18185 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
18186 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
18187 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
18188 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
18189 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
18190 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
18191 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
18192 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
18193 ep_38C1600->scsi_reset_delay =
18194 adv_dvc_varp->scsi_reset_wait;
18195 ep_38C1600->serial_number_word1 =
18196 adv_dvc_varp->cfg->serial1;
18197 ep_38C1600->serial_number_word2 =
18198 adv_dvc_varp->cfg->serial2;
18199 ep_38C1600->serial_number_word3 =
18200 adv_dvc_varp->cfg->serial3;
18201 }
18202
18203 /*
18204 * Set the adapter's target id bit in the 'init_tidmask' field.
18205 */
18206 boardp->init_tidmask |=
18207 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
18208
18209 /*
18210 * Finish initializing the 'Scsi_Host' structure.
18211 */
18212 shost->irq = adv_dvc_varp->irq_no;
18213 }
18214
18215 /*
18216 * Channels are numbered beginning with 0. For AdvanSys one host
18217 * structure supports one channel. Multi-channel boards have a
18218 * separate host structure for each channel.
18219 */
18220 shost->max_channel = 0;
18221 if (ASC_NARROW_BOARD(boardp)) {
18222 shost->max_id = ASC_MAX_TID + 1;
18223 shost->max_lun = ASC_MAX_LUN + 1;
18224
18225 shost->io_port = asc_dvc_varp->iop_base;
18226 boardp->asc_n_io_port = ASC_IOADR_GAP;
18227 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
18228
18229 /* Set maximum number of queues the adapter can handle. */
18230 shost->can_queue = asc_dvc_varp->max_total_qng;
18231 } else {
18232 shost->max_id = ADV_MAX_TID + 1;
18233 shost->max_lun = ADV_MAX_LUN + 1;
18234
18235 /*
18236 * Save the I/O Port address and length even though
18237 * I/O ports are not used to access Wide boards.
18238 * Instead the Wide boards are accessed with
18239 * PCI Memory Mapped I/O.
18240 */
18241 shost->io_port = iop;
18242 boardp->asc_n_io_port = iolen;
18243
18244 shost->this_id = adv_dvc_varp->chip_scsi_id;
18245
18246 /* Set maximum number of queues the adapter can handle. */
18247 shost->can_queue = adv_dvc_varp->max_host_qng;
18248 }
18249
18250 /*
18251 * 'n_io_port' currently is one byte.
18252 *
18253 * Set a value to 'n_io_port', but never referenced it because
18254 * it may be truncated.
18255 */
18256 shost->n_io_port = boardp->asc_n_io_port <= 255 ?
18257 boardp->asc_n_io_port : 255;
18258
18259 /*
18260 * Following v1.3.89, 'cmd_per_lun' is no longer needed
18261 * and should be set to zero.
18262 *
18263 * But because of a bug introduced in v1.3.89 if the driver is
18264 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
18265 * SCSI function 'allocate_device' will panic. To allow the driver
18266 * to work as a module in these kernels set 'cmd_per_lun' to 1.
18267 *
18268 * Note: This is wrong. cmd_per_lun should be set to the depth
18269 * you want on untagged devices always.
18270 #ifdef MODULE
18271 */
18272 shost->cmd_per_lun = 1;
18273/* #else
18274 shost->cmd_per_lun = 0;
18275#endif */
18276
18277 /*
18278 * Set the maximum number of scatter-gather elements the
18279 * adapter can handle.
18280 */
18281 if (ASC_NARROW_BOARD(boardp)) {
18282 /*
18283 * Allow two commands with 'sg_tablesize' scatter-gather
18284 * elements to be executed simultaneously. This value is
18285 * the theoretical hardware limit. It may be decreased
18286 * below.
18287 */
18288 shost->sg_tablesize =
18289 (((asc_dvc_varp->max_total_qng - 2) / 2) *
18290 ASC_SG_LIST_PER_Q) + 1;
18291 } else {
18292 shost->sg_tablesize = ADV_MAX_SG_LIST;
18293 }
18294
18295 /*
18296 * The value of 'sg_tablesize' can not exceed the SCSI
18297 * mid-level driver definition of SG_ALL. SG_ALL also
18298 * must not be exceeded, because it is used to define the
18299 * size of the scatter-gather table in 'struct asc_sg_head'.
18300 */
18301 if (shost->sg_tablesize > SG_ALL) {
18302 shost->sg_tablesize = SG_ALL;
18303 }
18304
18305 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
18306
18307 /* BIOS start address. */
18308 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018309 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
18310 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018311 } else {
18312 /*
18313 * Fill-in BIOS board variables. The Wide BIOS saves
18314 * information in LRAM that is used by the driver.
18315 */
18316 AdvReadWordLram(adv_dvc_varp->iop_base,
18317 BIOS_SIGNATURE, boardp->bios_signature);
18318 AdvReadWordLram(adv_dvc_varp->iop_base,
18319 BIOS_VERSION, boardp->bios_version);
18320 AdvReadWordLram(adv_dvc_varp->iop_base,
18321 BIOS_CODESEG, boardp->bios_codeseg);
18322 AdvReadWordLram(adv_dvc_varp->iop_base,
18323 BIOS_CODELEN, boardp->bios_codelen);
18324
18325 ASC_DBG2(1,
18326 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
18327 boardp->bios_signature, boardp->bios_version);
18328
18329 ASC_DBG2(1,
18330 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
18331 boardp->bios_codeseg, boardp->bios_codelen);
18332
18333 /*
18334 * If the BIOS saved a valid signature, then fill in
18335 * the BIOS code segment base address.
18336 */
18337 if (boardp->bios_signature == 0x55AA) {
18338 /*
18339 * Convert x86 realmode code segment to a linear
18340 * address by shifting left 4.
18341 */
18342 shost->base = ((ulong)boardp->bios_codeseg << 4);
18343 } else {
18344 shost->base = 0;
18345 }
18346 }
18347
18348 /*
18349 * Register Board Resources - I/O Port, DMA, IRQ
18350 */
18351
18352 /*
18353 * Register I/O port range.
18354 *
18355 * For Wide boards the I/O ports are not used to access
18356 * the board, but request the region anyway.
18357 *
18358 * 'shost->n_io_port' is not referenced, because it may be truncated.
18359 */
18360 ASC_DBG2(2,
18361 "advansys_board_found: request_region port 0x%lx, len 0x%x\n",
18362 (ulong)shost->io_port, boardp->asc_n_io_port);
18363 if (request_region(shost->io_port, boardp->asc_n_io_port,
18364 "advansys") == NULL) {
18365 ASC_PRINT3
18366 ("advansys_board_found: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
18367 boardp->id, (ulong)shost->io_port, boardp->asc_n_io_port);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018368 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018369 }
18370
18371 /* Register DMA Channel for Narrow boards. */
18372 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
18373#ifdef CONFIG_ISA
18374 if (ASC_NARROW_BOARD(boardp)) {
18375 /* Register DMA channel for ISA bus. */
18376 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
18377 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018378 ret = request_dma(shost->dma_channel, "advansys");
18379 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018380 ASC_PRINT3
18381 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
18382 boardp->id, shost->dma_channel, ret);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018383 goto err_free_region;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018384 }
18385 AscEnableIsaDma(shost->dma_channel);
18386 }
18387 }
18388#endif /* CONFIG_ISA */
18389
18390 /* Register IRQ Number. */
18391 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060018392
18393 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
18394 "advansys", shost);
18395
18396 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018397 if (ret == -EBUSY) {
18398 ASC_PRINT2
18399 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
18400 boardp->id, shost->irq);
18401 } else if (ret == -EINVAL) {
18402 ASC_PRINT2
18403 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
18404 boardp->id, shost->irq);
18405 } else {
18406 ASC_PRINT3
18407 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
18408 boardp->id, shost->irq, ret);
18409 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018410 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018411 }
18412
18413 /*
18414 * Initialize board RISC chip and enable interrupts.
18415 */
18416 if (ASC_NARROW_BOARD(boardp)) {
18417 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
18418 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
18419 err_code = asc_dvc_varp->err_code;
18420
18421 if (warn_code || err_code) {
18422 ASC_PRINT4
18423 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
18424 boardp->id,
18425 asc_dvc_varp->init_state, warn_code, err_code);
18426 }
18427 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018428 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018429 }
18430
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018431 if (err_code != 0)
18432 goto err_free_wide_mem;
18433
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018434 ASC_DBG_PRT_SCSI_HOST(2, shost);
18435
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018436 ret = scsi_add_host(shost, dev);
18437 if (ret)
18438 goto err_free_wide_mem;
18439
18440 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018441 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018442
18443 err_free_wide_mem:
18444 advansys_wide_free_mem(boardp);
18445 free_irq(shost->irq, shost);
18446 err_free_dma:
18447 if (shost->dma_channel != NO_ISA_DMA)
18448 free_dma(shost->dma_channel);
18449 err_free_region:
18450 release_region(shost->io_port, boardp->asc_n_io_port);
18451 err_free_proc:
18452 kfree(boardp->prtbuf);
18453 err_unmap:
18454 if (boardp->ioremap_addr)
18455 iounmap(boardp->ioremap_addr);
18456 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018457 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018458 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018459}
18460
18461/*
18462 * advansys_detect()
18463 *
18464 * Detect function for AdvanSys adapters.
18465 *
18466 * Argument is a pointer to the host driver's scsi_hosts entry.
18467 *
18468 * Return number of adapters found.
18469 *
18470 * Note: Because this function is called during system initialization
18471 * it must not call SCSI mid-level functions including scsi_malloc()
18472 * and scsi_free().
18473 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018474static int __init advansys_detect(void)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018475{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018476 int iop;
18477 int bus;
18478 int ioport = 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018479 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018481 ASC_DBG(1, "advansys_detect: begin\n");
18482
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018483 asc_legacy_count = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018484
18485 /*
18486 * If I/O port probing has been modified, then verify and
18487 * clean-up the 'asc_ioport' list.
18488 */
18489 if (asc_iopflag == ASC_TRUE) {
18490 for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
18491 ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
18492 ioport, asc_ioport[ioport]);
18493 if (asc_ioport[ioport] != 0) {
18494 for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX;
18495 iop++) {
18496 if (_asc_def_iop_base[iop] ==
18497 asc_ioport[ioport]) {
18498 break;
18499 }
18500 }
18501 if (iop == ASC_IOADR_TABLE_MAX_IX) {
18502 printk
18503 ("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
18504 asc_ioport[ioport]);
18505 asc_ioport[ioport] = 0;
18506 }
18507 }
18508 }
18509 ioport = 0;
18510 }
18511
18512 for (bus = 0; bus < ASC_NUM_BUS; bus++) {
18513
18514 ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
18515 bus, asc_bus_name[bus]);
18516 iop = 0;
18517
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018518 while (asc_legacy_count < ASC_NUM_BOARD_SUPPORTED) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018519
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018520 ASC_DBG1(2, "advansys_detect: asc_legacy_count %d\n",
18521 asc_legacy_count);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018522
18523 switch (asc_bus[bus]) {
18524 case ASC_IS_ISA:
18525 case ASC_IS_VL:
18526#ifdef CONFIG_ISA
18527 if (asc_iopflag == ASC_FALSE) {
18528 iop =
18529 AscSearchIOPortAddr(iop,
18530 asc_bus[bus]);
18531 } else {
18532 /*
18533 * ISA and VL I/O port scanning has either been
18534 * eliminated or limited to selected ports on
18535 * the LILO command line, /etc/lilo.conf, or
18536 * by setting variables when the module was loaded.
18537 */
18538 ASC_DBG(1,
18539 "advansys_detect: I/O port scanning modified\n");
18540 ioport_try_again:
18541 iop = 0;
18542 for (; ioport < ASC_NUM_IOPORT_PROBE;
18543 ioport++) {
18544 if ((iop =
18545 asc_ioport[ioport]) != 0) {
18546 break;
18547 }
18548 }
18549 if (iop) {
18550 ASC_DBG1(1,
18551 "advansys_detect: probing I/O port 0x%x...\n",
18552 iop);
18553 if (!request_region
18554 (iop, ASC_IOADR_GAP,
18555 "advansys")) {
18556 printk
18557 ("AdvanSys SCSI: specified I/O Port 0x%X is busy\n",
18558 iop);
18559 /* Don't try this I/O port twice. */
18560 asc_ioport[ioport] = 0;
18561 goto ioport_try_again;
18562 } else if (AscFindSignature(iop)
18563 == ASC_FALSE) {
18564 printk
18565 ("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n",
18566 iop);
18567 /* Don't try this I/O port twice. */
18568 release_region(iop,
18569 ASC_IOADR_GAP);
18570 asc_ioport[ioport] = 0;
18571 goto ioport_try_again;
18572 } else {
18573 /*
18574 * If this isn't an ISA board, then it must be
18575 * a VL board. If currently looking an ISA
18576 * board is being looked for then try for
18577 * another ISA board in 'asc_ioport'.
18578 */
18579 if (asc_bus[bus] ==
18580 ASC_IS_ISA
18581 &&
18582 (AscGetChipVersion
18583 (iop,
18584 ASC_IS_ISA) &
18585 ASC_CHIP_VER_ISA_BIT)
18586 == 0) {
18587 /*
18588 * Don't clear 'asc_ioport[ioport]'. Try
18589 * this board again for VL. Increment
18590 * 'ioport' past this board.
18591 */
18592 ioport++;
18593 release_region
18594 (iop,
18595 ASC_IOADR_GAP);
18596 goto ioport_try_again;
18597 }
18598 }
18599 /*
18600 * This board appears good, don't try the I/O port
18601 * again by clearing its value. Increment 'ioport'
18602 * for the next iteration.
18603 */
18604 asc_ioport[ioport++] = 0;
18605 }
18606 }
18607#endif /* CONFIG_ISA */
18608 break;
18609
18610 case ASC_IS_EISA:
18611#ifdef CONFIG_ISA
18612 iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
18613#endif /* CONFIG_ISA */
18614 break;
18615
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018616 default:
18617 ASC_PRINT1
18618 ("advansys_detect: unknown bus type: %d\n",
18619 asc_bus[bus]);
18620 break;
18621 }
18622 ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
18623
18624 /*
18625 * Adapter not found, try next bus type.
18626 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018627 if (iop == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018628 break;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018629
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018630 shost = advansys_board_found(iop, NULL, asc_bus[bus]);
18631 if (shost) {
18632 asc_host[asc_legacy_count++] = shost;
18633 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018634 }
18635 }
18636
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018637 ASC_DBG1(1, "advansys_detect: done: asc_legacy_count %d\n",
18638 asc_legacy_count);
18639 return asc_legacy_count;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018640}
18641
18642/*
18643 * advansys_release()
18644 *
18645 * Release resources allocated for a single AdvanSys adapter.
18646 */
18647static int advansys_release(struct Scsi_Host *shost)
18648{
18649 asc_board_t *boardp;
18650
18651 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018652 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018653 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060018654 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018655 if (shost->dma_channel != NO_ISA_DMA) {
18656 ASC_DBG(1, "advansys_release: free_dma()\n");
18657 free_dma(shost->dma_channel);
18658 }
18659 release_region(shost->io_port, boardp->asc_n_io_port);
18660 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018661 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018662 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018663 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018664 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018665 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018666 ASC_DBG(1, "advansys_release: end\n");
18667 return 0;
18668}
18669
Dave Jones2672ea82006-08-02 17:11:49 -040018670/* PCI Devices supported by this driver */
18671static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018672 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
18673 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18674 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
18675 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18676 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
18677 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18678 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
18679 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18680 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
18681 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18682 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
18683 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18684 {}
Dave Jones2672ea82006-08-02 17:11:49 -040018685};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018686
Dave Jones2672ea82006-08-02 17:11:49 -040018687MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018688
18689static int __devinit
18690advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
18691{
18692 int err, ioport;
18693 struct Scsi_Host *shost;
18694
18695 err = pci_enable_device(pdev);
18696 if (err)
18697 goto fail;
18698
18699 if (pci_resource_len(pdev, 0) == 0)
18700 goto nodev;
18701
18702 ioport = pci_resource_start(pdev, 0);
18703 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
18704
18705 if (!shost)
18706 goto nodev;
18707
18708 pci_set_drvdata(pdev, shost);
18709 return 0;
18710
18711 nodev:
18712 err = -ENODEV;
18713 pci_disable_device(pdev);
18714 fail:
18715 return err;
18716}
18717
18718static void __devexit advansys_pci_remove(struct pci_dev *pdev)
18719{
18720 advansys_release(pci_get_drvdata(pdev));
18721 pci_disable_device(pdev);
18722}
18723
18724static struct pci_driver advansys_pci_driver = {
18725 .name = "advansys",
18726 .id_table = advansys_pci_tbl,
18727 .probe = advansys_pci_probe,
18728 .remove = __devexit_p(advansys_pci_remove),
18729};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018730
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018731static int __init advansys_init(void)
18732{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018733 int i, error;
18734 advansys_detect();
18735 error = pci_register_driver(&advansys_pci_driver);
18736 if (error)
18737 goto fail;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018738
18739 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018740
18741 fail:
18742 for (i = 0; i < asc_legacy_count; i++)
18743 advansys_release(asc_host[i]);
18744
18745 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018746}
18747
18748static void __exit advansys_exit(void)
18749{
18750 int i;
18751
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018752 pci_unregister_driver(&advansys_pci_driver);
18753
18754 for (i = 0; i < asc_legacy_count; i++)
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018755 advansys_release(asc_host[i]);
18756}
18757
18758module_init(advansys_init);
18759module_exit(advansys_exit);
18760
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018761MODULE_LICENSE("GPL");