blob: e79f7955f6eacb2077cb46c9a9810650e43fe7ec [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
Matthew Wilcoxc304ec92007-07-30 09:18:45 -0600283 /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
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 Wilcoxc304ec92007-07-30 09:18:45 -0600772#include <linux/isa.h>
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -0600773#include <linux/eisa.h>
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -0400774#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775#include <linux/spinlock.h>
776#include <linux/dma-mapping.h>
777
778#include <asm/io.h>
779#include <asm/system.h>
780#include <asm/dma.h>
781
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -0400782#include <scsi/scsi_cmnd.h>
783#include <scsi/scsi_device.h>
784#include <scsi/scsi_tcq.h>
785#include <scsi/scsi.h>
786#include <scsi/scsi_host.h>
787
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -0600788/* FIXME: (by jejb@steeleye.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 *
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -0600790 * Although all of the necessary command mapping places have the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 * appropriate dma_map.. APIs, the driver still processes its internal
792 * queue using bus_to_virt() and virt_to_bus() which are illegal under
793 * the API. The entire queue processing structure will need to be
794 * altered to fix this.
795 */
796#warning this driver is still not properly converted to the DMA API
797
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798/*
799 * --- Driver Options
800 */
801
802/* Enable driver assertions. */
803#define ADVANSYS_ASSERT
804
805/* Enable driver /proc statistics. */
806#define ADVANSYS_STATS
807
808/* Enable driver tracing. */
809/* #define ADVANSYS_DEBUG */
810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811/*
812 * --- Asc Library Constants and Macros
813 */
814
815#define ASC_LIB_VERSION_MAJOR 1
816#define ASC_LIB_VERSION_MINOR 24
817#define ASC_LIB_SERIAL_NUMBER 123
818
819/*
820 * Portable Data Types
821 *
822 * Any instance where a 32-bit long or pointer type is assumed
823 * for precision or HW defined structures, the following define
824 * types must be used. In Linux the char, short, and int types
825 * are all consistent at 8, 16, and 32 bits respectively. Pointers
826 * and long types are 64 bits on Alpha and UltraSPARC.
827 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400828#define ASC_PADDR __u32 /* Physical/Bus address data type. */
829#define ASC_VADDR __u32 /* Virtual address data type. */
830#define ASC_DCNT __u32 /* Unsigned Data count type. */
831#define ASC_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833/*
834 * These macros are used to convert a virtual address to a
835 * 32-bit value. This currently can be used on Linux Alpha
836 * which uses 64-bit virtual address but a 32-bit bus address.
837 * This is likely to break in the future, but doing this now
838 * will give us time to change the HW and FW to handle 64-bit
839 * addresses.
840 */
841#define ASC_VADDR_TO_U32 virt_to_bus
842#define ASC_U32_TO_VADDR bus_to_virt
843
844typedef unsigned char uchar;
845
846#ifndef TRUE
847#define TRUE (1)
848#endif
849#ifndef FALSE
850#define FALSE (0)
851#endif
852
853#define EOF (-1)
854#define ERR (-1)
855#define UW_ERR (uint)(0xFFFF)
856#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
858#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
860#define ASC_DVCLIB_CALL_DONE (1)
861#define ASC_DVCLIB_CALL_FAILED (0)
862#define ASC_DVCLIB_CALL_ERROR (-1)
863
Dave Jones2672ea82006-08-02 17:11:49 -0400864#define PCI_VENDOR_ID_ASP 0x10cd
865#define PCI_DEVICE_ID_ASP_1200A 0x1100
866#define PCI_DEVICE_ID_ASP_ABP940 0x1200
867#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
868#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
869#define PCI_DEVICE_ID_38C0800_REV1 0x2500
870#define PCI_DEVICE_ID_38C1600_REV1 0x2700
871
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872/*
873 * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
874 * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
875 * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
876 * SRB structure.
877 */
878#define CC_VERY_LONG_SG_LIST 0
879#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
880
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400881#define PortAddr unsigned short /* port address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882#define inp(port) inb(port)
883#define outp(port, byte) outb((byte), (port))
884
885#define inpw(port) inw(port)
886#define outpw(port, word) outw((word), (port))
887
888#define ASC_MAX_SG_QUEUE 7
889#define ASC_MAX_SG_LIST 255
890
891#define ASC_CS_TYPE unsigned short
892
893#define ASC_IS_ISA (0x0001)
894#define ASC_IS_ISAPNP (0x0081)
895#define ASC_IS_EISA (0x0002)
896#define ASC_IS_PCI (0x0004)
897#define ASC_IS_PCI_ULTRA (0x0104)
898#define ASC_IS_PCMCIA (0x0008)
899#define ASC_IS_MCA (0x0020)
900#define ASC_IS_VL (0x0040)
901#define ASC_ISA_PNP_PORT_ADDR (0x279)
902#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
903#define ASC_IS_WIDESCSI_16 (0x0100)
904#define ASC_IS_WIDESCSI_32 (0x0200)
905#define ASC_IS_BIG_ENDIAN (0x8000)
906#define ASC_CHIP_MIN_VER_VL (0x01)
907#define ASC_CHIP_MAX_VER_VL (0x07)
908#define ASC_CHIP_MIN_VER_PCI (0x09)
909#define ASC_CHIP_MAX_VER_PCI (0x0F)
910#define ASC_CHIP_VER_PCI_BIT (0x08)
911#define ASC_CHIP_MIN_VER_ISA (0x11)
912#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
913#define ASC_CHIP_MAX_VER_ISA (0x27)
914#define ASC_CHIP_VER_ISA_BIT (0x30)
915#define ASC_CHIP_VER_ISAPNP_BIT (0x20)
916#define ASC_CHIP_VER_ASYN_BUG (0x21)
917#define ASC_CHIP_VER_PCI 0x08
918#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02)
919#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03)
920#define ASC_CHIP_MIN_VER_EISA (0x41)
921#define ASC_CHIP_MAX_VER_EISA (0x47)
922#define ASC_CHIP_VER_EISA_BIT (0x40)
923#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
924#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21
925#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A
926#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL)
927#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
928#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL)
929#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
930#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL)
931#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
932#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
933#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
934
935#define ASC_SCSI_ID_BITS 3
936#define ASC_SCSI_TIX_TYPE uchar
937#define ASC_ALL_DEVICE_BIT_SET 0xFF
938#define ASC_SCSI_BIT_ID_TYPE uchar
939#define ASC_MAX_TID 7
940#define ASC_MAX_LUN 7
941#define ASC_SCSI_WIDTH_BIT_SET 0xFF
942#define ASC_MAX_SENSE_LEN 32
943#define ASC_MIN_SENSE_LEN 14
944#define ASC_MAX_CDB_LEN 12
945#define ASC_SCSI_RESET_HOLD_TIME_US 60
946
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947/*
948 * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
949 * and CmdDt (Command Support Data) field bit definitions.
950 */
951#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3
952#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2
953#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1
954#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0
955
956#define ASC_SCSIDIR_NOCHK 0x00
957#define ASC_SCSIDIR_T2H 0x08
958#define ASC_SCSIDIR_H2T 0x10
959#define ASC_SCSIDIR_NODATA 0x18
960#define SCSI_ASC_NOMEDIA 0x3A
961#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
962#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
963#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
964#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965#define MS_SDTR_LEN 0x03
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966#define MS_WDTR_LEN 0x02
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
968#define ASC_SG_LIST_PER_Q 7
969#define QS_FREE 0x00
970#define QS_READY 0x01
971#define QS_DISC1 0x02
972#define QS_DISC2 0x04
973#define QS_BUSY 0x08
974#define QS_ABORTED 0x40
975#define QS_DONE 0x80
976#define QC_NO_CALLBACK 0x01
977#define QC_SG_SWAP_QUEUE 0x02
978#define QC_SG_HEAD 0x04
979#define QC_DATA_IN 0x08
980#define QC_DATA_OUT 0x10
981#define QC_URGENT 0x20
982#define QC_MSG_OUT 0x40
983#define QC_REQ_SENSE 0x80
984#define QCSG_SG_XFER_LIST 0x02
985#define QCSG_SG_XFER_MORE 0x04
986#define QCSG_SG_XFER_END 0x08
987#define QD_IN_PROGRESS 0x00
988#define QD_NO_ERROR 0x01
989#define QD_ABORTED_BY_HOST 0x02
990#define QD_WITH_ERROR 0x04
991#define QD_INVALID_REQUEST 0x80
992#define QD_INVALID_HOST_NUM 0x81
993#define QD_INVALID_DEVICE 0x82
994#define QD_ERR_INTERNAL 0xFF
995#define QHSTA_NO_ERROR 0x00
996#define QHSTA_M_SEL_TIMEOUT 0x11
997#define QHSTA_M_DATA_OVER_RUN 0x12
998#define QHSTA_M_DATA_UNDER_RUN 0x12
999#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
1000#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
1001#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
1002#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
1003#define QHSTA_D_HOST_ABORT_FAILED 0x23
1004#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
1005#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
1006#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
1007#define QHSTA_M_WTM_TIMEOUT 0x41
1008#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
1009#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
1010#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
1011#define QHSTA_M_TARGET_STATUS_BUSY 0x45
1012#define QHSTA_M_BAD_TAG_CODE 0x46
1013#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
1014#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
1015#define QHSTA_D_LRAM_CMP_ERROR 0x81
1016#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
1017#define ASC_FLAG_SCSIQ_REQ 0x01
1018#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02
1019#define ASC_FLAG_BIOS_ASYNC_IO 0x04
1020#define ASC_FLAG_SRB_LINEAR_ADDR 0x08
1021#define ASC_FLAG_WIN16 0x10
1022#define ASC_FLAG_WIN32 0x20
1023#define ASC_FLAG_ISA_OVER_16MB 0x40
1024#define ASC_FLAG_DOS_VM_CALLBACK 0x80
1025#define ASC_TAG_FLAG_EXTRA_BYTES 0x10
1026#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04
1027#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
1028#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
1029#define ASC_SCSIQ_CPY_BEG 4
1030#define ASC_SCSIQ_SGHD_CPY_BEG 2
1031#define ASC_SCSIQ_B_FWD 0
1032#define ASC_SCSIQ_B_BWD 1
1033#define ASC_SCSIQ_B_STATUS 2
1034#define ASC_SCSIQ_B_QNO 3
1035#define ASC_SCSIQ_B_CNTL 4
1036#define ASC_SCSIQ_B_SG_QUEUE_CNT 5
1037#define ASC_SCSIQ_D_DATA_ADDR 8
1038#define ASC_SCSIQ_D_DATA_CNT 12
1039#define ASC_SCSIQ_B_SENSE_LEN 20
1040#define ASC_SCSIQ_DONE_INFO_BEG 22
1041#define ASC_SCSIQ_D_SRBPTR 22
1042#define ASC_SCSIQ_B_TARGET_IX 26
1043#define ASC_SCSIQ_B_CDB_LEN 28
1044#define ASC_SCSIQ_B_TAG_CODE 29
1045#define ASC_SCSIQ_W_VM_ID 30
1046#define ASC_SCSIQ_DONE_STATUS 32
1047#define ASC_SCSIQ_HOST_STATUS 33
1048#define ASC_SCSIQ_SCSI_STATUS 34
1049#define ASC_SCSIQ_CDB_BEG 36
1050#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
1051#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
1052#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
1053#define ASC_SCSIQ_B_SG_WK_QP 49
1054#define ASC_SCSIQ_B_SG_WK_IX 50
1055#define ASC_SCSIQ_W_ALT_DC1 52
1056#define ASC_SCSIQ_B_LIST_CNT 6
1057#define ASC_SCSIQ_B_CUR_LIST_CNT 7
1058#define ASC_SGQ_B_SG_CNTL 4
1059#define ASC_SGQ_B_SG_HEAD_QP 5
1060#define ASC_SGQ_B_SG_LIST_CNT 6
1061#define ASC_SGQ_B_SG_CUR_LIST_CNT 7
1062#define ASC_SGQ_LIST_BEG 8
1063#define ASC_DEF_SCSI1_QNG 4
1064#define ASC_MAX_SCSI1_QNG 4
1065#define ASC_DEF_SCSI2_QNG 16
1066#define ASC_MAX_SCSI2_QNG 32
1067#define ASC_TAG_CODE_MASK 0x23
1068#define ASC_STOP_REQ_RISC_STOP 0x01
1069#define ASC_STOP_ACK_RISC_STOP 0x03
1070#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10
1071#define ASC_STOP_CLEAN_UP_DISC_Q 0x20
1072#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
1073#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
1074#define ASC_TID_TO_TARGET_ID(tid) (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
1075#define ASC_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ASC_MAX_TID))
1076#define ASC_TIX_TO_TID(tix) ((tix) & ASC_MAX_TID)
1077#define ASC_TID_TO_TIX(tid) ((tid) & ASC_MAX_TID)
1078#define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
1079#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
1080
1081typedef struct asc_scsiq_1 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001082 uchar status;
1083 uchar q_no;
1084 uchar cntl;
1085 uchar sg_queue_cnt;
1086 uchar target_id;
1087 uchar target_lun;
1088 ASC_PADDR data_addr;
1089 ASC_DCNT data_cnt;
1090 ASC_PADDR sense_addr;
1091 uchar sense_len;
1092 uchar extra_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093} ASC_SCSIQ_1;
1094
1095typedef struct asc_scsiq_2 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001096 ASC_VADDR srb_ptr;
1097 uchar target_ix;
1098 uchar flag;
1099 uchar cdb_len;
1100 uchar tag_code;
1101 ushort vm_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102} ASC_SCSIQ_2;
1103
1104typedef struct asc_scsiq_3 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001105 uchar done_stat;
1106 uchar host_stat;
1107 uchar scsi_stat;
1108 uchar scsi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109} ASC_SCSIQ_3;
1110
1111typedef struct asc_scsiq_4 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001112 uchar cdb[ASC_MAX_CDB_LEN];
1113 uchar y_first_sg_list_qp;
1114 uchar y_working_sg_qp;
1115 uchar y_working_sg_ix;
1116 uchar y_res;
1117 ushort x_req_count;
1118 ushort x_reconnect_rtn;
1119 ASC_PADDR x_saved_data_addr;
1120 ASC_DCNT x_saved_data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121} ASC_SCSIQ_4;
1122
1123typedef struct asc_q_done_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001124 ASC_SCSIQ_2 d2;
1125 ASC_SCSIQ_3 d3;
1126 uchar q_status;
1127 uchar q_no;
1128 uchar cntl;
1129 uchar sense_len;
1130 uchar extra_bytes;
1131 uchar res;
1132 ASC_DCNT remain_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133} ASC_QDONE_INFO;
1134
1135typedef struct asc_sg_list {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001136 ASC_PADDR addr;
1137 ASC_DCNT bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138} ASC_SG_LIST;
1139
1140typedef struct asc_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001141 ushort entry_cnt;
1142 ushort queue_cnt;
1143 ushort entry_to_copy;
1144 ushort res;
1145 ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146} ASC_SG_HEAD;
1147
1148#define ASC_MIN_SG_LIST 2
1149
1150typedef struct asc_min_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001151 ushort entry_cnt;
1152 ushort queue_cnt;
1153 ushort entry_to_copy;
1154 ushort res;
1155 ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156} ASC_MIN_SG_HEAD;
1157
1158#define QCX_SORT (0x0001)
1159#define QCX_COALEASE (0x0002)
1160
1161typedef struct asc_scsi_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001162 ASC_SCSIQ_1 q1;
1163 ASC_SCSIQ_2 q2;
1164 uchar *cdbptr;
1165 ASC_SG_HEAD *sg_head;
1166 ushort remain_sg_entry_cnt;
1167 ushort next_sg_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168} ASC_SCSI_Q;
1169
1170typedef struct asc_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001171 ASC_SCSIQ_1 r1;
1172 ASC_SCSIQ_2 r2;
1173 uchar *cdbptr;
1174 ASC_SG_HEAD *sg_head;
1175 uchar *sense_ptr;
1176 ASC_SCSIQ_3 r3;
1177 uchar cdb[ASC_MAX_CDB_LEN];
1178 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179} ASC_SCSI_REQ_Q;
1180
1181typedef struct asc_scsi_bios_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001182 ASC_SCSIQ_1 r1;
1183 ASC_SCSIQ_2 r2;
1184 uchar *cdbptr;
1185 ASC_SG_HEAD *sg_head;
1186 uchar *sense_ptr;
1187 ASC_SCSIQ_3 r3;
1188 uchar cdb[ASC_MAX_CDB_LEN];
1189 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190} ASC_SCSI_BIOS_REQ_Q;
1191
1192typedef struct asc_risc_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001193 uchar fwd;
1194 uchar bwd;
1195 ASC_SCSIQ_1 i1;
1196 ASC_SCSIQ_2 i2;
1197 ASC_SCSIQ_3 i3;
1198 ASC_SCSIQ_4 i4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199} ASC_RISC_Q;
1200
1201typedef struct asc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001202 uchar seq_no;
1203 uchar q_no;
1204 uchar cntl;
1205 uchar sg_head_qp;
1206 uchar sg_list_cnt;
1207 uchar sg_cur_list_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208} ASC_SG_LIST_Q;
1209
1210typedef struct asc_risc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001211 uchar fwd;
1212 uchar bwd;
1213 ASC_SG_LIST_Q sg;
1214 ASC_SG_LIST sg_list[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215} ASC_RISC_SG_LIST_Q;
1216
1217#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
1218#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024
1219#define ASCQ_ERR_NO_ERROR 0
1220#define ASCQ_ERR_IO_NOT_FOUND 1
1221#define ASCQ_ERR_LOCAL_MEM 2
1222#define ASCQ_ERR_CHKSUM 3
1223#define ASCQ_ERR_START_CHIP 4
1224#define ASCQ_ERR_INT_TARGET_ID 5
1225#define ASCQ_ERR_INT_LOCAL_MEM 6
1226#define ASCQ_ERR_HALT_RISC 7
1227#define ASCQ_ERR_GET_ASPI_ENTRY 8
1228#define ASCQ_ERR_CLOSE_ASPI 9
1229#define ASCQ_ERR_HOST_INQUIRY 0x0A
1230#define ASCQ_ERR_SAVED_SRB_BAD 0x0B
1231#define ASCQ_ERR_QCNTL_SG_LIST 0x0C
1232#define ASCQ_ERR_Q_STATUS 0x0D
1233#define ASCQ_ERR_WR_SCSIQ 0x0E
1234#define ASCQ_ERR_PC_ADDR 0x0F
1235#define ASCQ_ERR_SYN_OFFSET 0x10
1236#define ASCQ_ERR_SYN_XFER_TIME 0x11
1237#define ASCQ_ERR_LOCK_DMA 0x12
1238#define ASCQ_ERR_UNLOCK_DMA 0x13
1239#define ASCQ_ERR_VDS_CHK_INSTALL 0x14
1240#define ASCQ_ERR_MICRO_CODE_HALT 0x15
1241#define ASCQ_ERR_SET_LRAM_ADDR 0x16
1242#define ASCQ_ERR_CUR_QNG 0x17
1243#define ASCQ_ERR_SG_Q_LINKS 0x18
1244#define ASCQ_ERR_SCSIQ_PTR 0x19
1245#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
1246#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
1247#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
1248#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D
1249#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
1250#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F
1251#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20
1252#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21
1253#define ASCQ_ERR_SEND_SCSI_Q 0x22
1254#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23
1255#define ASCQ_ERR_RESET_SDTR 0x24
1256
1257/*
1258 * Warning code values are set in ASC_DVC_VAR 'warn_code'.
1259 */
1260#define ASC_WARN_NO_ERROR 0x0000
1261#define ASC_WARN_IO_PORT_ROTATE 0x0001
1262#define ASC_WARN_EEPROM_CHKSUM 0x0002
1263#define ASC_WARN_IRQ_MODIFIED 0x0004
1264#define ASC_WARN_AUTO_CONFIG 0x0008
1265#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
1266#define ASC_WARN_EEPROM_RECOVER 0x0020
1267#define ASC_WARN_CFG_MSW_RECOVER 0x0040
1268#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
1269
1270/*
1271 * Error code values are set in ASC_DVC_VAR 'err_code'.
1272 */
1273#define ASC_IERR_WRITE_EEPROM 0x0001
1274#define ASC_IERR_MCODE_CHKSUM 0x0002
1275#define ASC_IERR_SET_PC_ADDR 0x0004
1276#define ASC_IERR_START_STOP_CHIP 0x0008
1277#define ASC_IERR_IRQ_NO 0x0010
1278#define ASC_IERR_SET_IRQ_NO 0x0020
1279#define ASC_IERR_CHIP_VERSION 0x0040
1280#define ASC_IERR_SET_SCSI_ID 0x0080
1281#define ASC_IERR_GET_PHY_ADDR 0x0100
1282#define ASC_IERR_BAD_SIGNATURE 0x0200
1283#define ASC_IERR_NO_BUS_TYPE 0x0400
1284#define ASC_IERR_SCAM 0x0800
1285#define ASC_IERR_SET_SDTR 0x1000
1286#define ASC_IERR_RW_LRAM 0x8000
1287
1288#define ASC_DEF_IRQ_NO 10
1289#define ASC_MAX_IRQ_NO 15
1290#define ASC_MIN_IRQ_NO 10
1291#define ASC_MIN_REMAIN_Q (0x02)
1292#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
1293#define ASC_MIN_TAG_Q_PER_DVC (0x04)
1294#define ASC_DEF_TAG_Q_PER_DVC (0x04)
1295#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q
1296#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
1297#define ASC_MAX_TOTAL_QNG 240
1298#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
1299#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
1300#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
1301#define ASC_MAX_INRAM_TAG_QNG 16
1302#define ASC_IOADR_TABLE_MAX_IX 11
1303#define ASC_IOADR_GAP 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304#define ASC_LIB_SCSIQ_WK_SP 256
1305#define ASC_MAX_SYN_XFER_NO 16
1306#define ASC_SYN_MAX_OFFSET 0x0F
1307#define ASC_DEF_SDTR_OFFSET 0x0F
1308#define ASC_DEF_SDTR_INDEX 0x00
1309#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
1310#define SYN_XFER_NS_0 25
1311#define SYN_XFER_NS_1 30
1312#define SYN_XFER_NS_2 35
1313#define SYN_XFER_NS_3 40
1314#define SYN_XFER_NS_4 50
1315#define SYN_XFER_NS_5 60
1316#define SYN_XFER_NS_6 70
1317#define SYN_XFER_NS_7 85
1318#define SYN_ULTRA_XFER_NS_0 12
1319#define SYN_ULTRA_XFER_NS_1 19
1320#define SYN_ULTRA_XFER_NS_2 25
1321#define SYN_ULTRA_XFER_NS_3 32
1322#define SYN_ULTRA_XFER_NS_4 38
1323#define SYN_ULTRA_XFER_NS_5 44
1324#define SYN_ULTRA_XFER_NS_6 50
1325#define SYN_ULTRA_XFER_NS_7 57
1326#define SYN_ULTRA_XFER_NS_8 63
1327#define SYN_ULTRA_XFER_NS_9 69
1328#define SYN_ULTRA_XFER_NS_10 75
1329#define SYN_ULTRA_XFER_NS_11 82
1330#define SYN_ULTRA_XFER_NS_12 88
1331#define SYN_ULTRA_XFER_NS_13 94
1332#define SYN_ULTRA_XFER_NS_14 100
1333#define SYN_ULTRA_XFER_NS_15 107
1334
1335typedef struct ext_msg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001336 uchar msg_type;
1337 uchar msg_len;
1338 uchar msg_req;
1339 union {
1340 struct {
1341 uchar sdtr_xfer_period;
1342 uchar sdtr_req_ack_offset;
1343 } sdtr;
1344 struct {
1345 uchar wdtr_width;
1346 } wdtr;
1347 struct {
1348 uchar mdp_b3;
1349 uchar mdp_b2;
1350 uchar mdp_b1;
1351 uchar mdp_b0;
1352 } mdp;
1353 } u_ext_msg;
1354 uchar res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355} EXT_MSG;
1356
1357#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
1358#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
1359#define wdtr_width u_ext_msg.wdtr.wdtr_width
1360#define mdp_b3 u_ext_msg.mdp_b3
1361#define mdp_b2 u_ext_msg.mdp_b2
1362#define mdp_b1 u_ext_msg.mdp_b1
1363#define mdp_b0 u_ext_msg.mdp_b0
1364
1365typedef struct asc_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001366 ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
1367 ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
1368 ASC_SCSI_BIT_ID_TYPE disc_enable;
1369 ASC_SCSI_BIT_ID_TYPE sdtr_enable;
1370 uchar chip_scsi_id;
1371 uchar isa_dma_speed;
1372 uchar isa_dma_channel;
1373 uchar chip_version;
1374 ushort lib_serial_no;
1375 ushort lib_version;
1376 ushort mcode_date;
1377 ushort mcode_version;
1378 uchar max_tag_qng[ASC_MAX_TID + 1];
1379 uchar *overrun_buf;
1380 uchar sdtr_period_offset[ASC_MAX_TID + 1];
1381 ushort pci_slot_info;
1382 uchar adapter_info[6];
1383 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384} ASC_DVC_CFG;
1385
1386#define ASC_DEF_DVC_CNTL 0xFFFF
1387#define ASC_DEF_CHIP_SCSI_ID 7
1388#define ASC_DEF_ISA_DMA_SPEED 4
1389#define ASC_INIT_STATE_NULL 0x0000
1390#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
1391#define ASC_INIT_STATE_END_GET_CFG 0x0002
1392#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
1393#define ASC_INIT_STATE_END_SET_CFG 0x0008
1394#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
1395#define ASC_INIT_STATE_END_LOAD_MC 0x0020
1396#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
1397#define ASC_INIT_STATE_END_INQUIRY 0x0080
1398#define ASC_INIT_RESET_SCSI_DONE 0x0100
1399#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
1401#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
1402#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
1403#define ASC_MIN_TAGGED_CMD 7
1404#define ASC_MAX_SCSI_RESET_WAIT 30
1405
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001406struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001408typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
1409typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
1411typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001412 PortAddr iop_base;
1413 ushort err_code;
1414 ushort dvc_cntl;
1415 ushort bug_fix_cntl;
1416 ushort bus_type;
1417 ASC_ISR_CALLBACK isr_callback;
1418 ASC_EXE_CALLBACK exe_callback;
1419 ASC_SCSI_BIT_ID_TYPE init_sdtr;
1420 ASC_SCSI_BIT_ID_TYPE sdtr_done;
1421 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
1422 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
1423 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
1424 ASC_SCSI_BIT_ID_TYPE start_motor;
1425 uchar scsi_reset_wait;
1426 uchar chip_no;
1427 char is_in_int;
1428 uchar max_total_qng;
1429 uchar cur_total_qng;
1430 uchar in_critical_cnt;
1431 uchar irq_no;
1432 uchar last_q_shortage;
1433 ushort init_state;
1434 uchar cur_dvc_qng[ASC_MAX_TID + 1];
1435 uchar max_dvc_qng[ASC_MAX_TID + 1];
1436 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
1437 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
1438 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
1439 ASC_DVC_CFG *cfg;
1440 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
1441 char redo_scam;
1442 ushort res2;
1443 uchar dos_int13_table[ASC_MAX_TID + 1];
1444 ASC_DCNT max_dma_count;
1445 ASC_SCSI_BIT_ID_TYPE no_scam;
1446 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
1447 uchar max_sdtr_index;
1448 uchar host_init_sdtr_index;
1449 struct asc_board *drv_ptr;
1450 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451} ASC_DVC_VAR;
1452
1453typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001454 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455} ASC_DVC_INQ_INFO;
1456
1457typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001458 ASC_DCNT lba;
1459 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460} ASC_CAP_INFO;
1461
1462typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001463 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464} ASC_CAP_INFO_ARRAY;
1465
1466#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
1467#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
1468#define ASC_CNTL_INITIATOR (ushort)0x0001
1469#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
1470#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
1471#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
1472#define ASC_CNTL_NO_SCAM (ushort)0x0010
1473#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
1474#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
1475#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
1476#define ASC_CNTL_RESET_SCSI (ushort)0x0200
1477#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
1478#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
1479#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
1480#define ASC_CNTL_BURST_MODE (ushort)0x2000
1481#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
1482#define ASC_EEP_DVC_CFG_BEG_VL 2
1483#define ASC_EEP_MAX_DVC_ADDR_VL 15
1484#define ASC_EEP_DVC_CFG_BEG 32
1485#define ASC_EEP_MAX_DVC_ADDR 45
1486#define ASC_EEP_DEFINED_WORDS 10
1487#define ASC_EEP_MAX_ADDR 63
1488#define ASC_EEP_RES_WORDS 0
1489#define ASC_EEP_MAX_RETRY 20
1490#define ASC_MAX_INIT_BUSY_RETRY 8
1491#define ASC_EEP_ISA_PNP_WSIZE 16
1492
1493/*
1494 * These macros keep the chip SCSI id and ISA DMA speed
1495 * bitfields in board order. C bitfields aren't portable
1496 * between big and little-endian platforms so they are
1497 * not used.
1498 */
1499
1500#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
1501#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
1502#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
1503 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
1504#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
1505 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
1506
1507typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001508 ushort cfg_lsw;
1509 ushort cfg_msw;
1510 uchar init_sdtr;
1511 uchar disc_enable;
1512 uchar use_cmd_qng;
1513 uchar start_motor;
1514 uchar max_total_qng;
1515 uchar max_tag_qng;
1516 uchar bios_scan;
1517 uchar power_up_wait;
1518 uchar no_scam;
1519 uchar id_speed; /* low order 4 bits is chip scsi id */
1520 /* high order 4 bits is isa dma speed */
1521 uchar dos_int13_table[ASC_MAX_TID + 1];
1522 uchar adapter_info[6];
1523 ushort cntl;
1524 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525} ASCEEP_CONFIG;
1526
1527#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
1528#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
1529#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
1530
1531#define ASC_EEP_CMD_READ 0x80
1532#define ASC_EEP_CMD_WRITE 0x40
1533#define ASC_EEP_CMD_WRITE_ABLE 0x30
1534#define ASC_EEP_CMD_WRITE_DISABLE 0x00
1535#define ASC_OVERRUN_BSIZE 0x00000048UL
1536#define ASC_CTRL_BREAK_ONCE 0x0001
1537#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
1538#define ASCV_MSGOUT_BEG 0x0000
1539#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
1540#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
1541#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
1542#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
1543#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
1544#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
1545#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
1546#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
1547#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
1548#define ASCV_BREAK_ADDR (ushort)0x0028
1549#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
1550#define ASCV_BREAK_CONTROL (ushort)0x002C
1551#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
1552
1553#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
1554#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
1555#define ASCV_MCODE_SIZE_W (ushort)0x0034
1556#define ASCV_STOP_CODE_B (ushort)0x0036
1557#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
1558#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
1559#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
1560#define ASCV_HALTCODE_W (ushort)0x0040
1561#define ASCV_CHKSUM_W (ushort)0x0042
1562#define ASCV_MC_DATE_W (ushort)0x0044
1563#define ASCV_MC_VER_W (ushort)0x0046
1564#define ASCV_NEXTRDY_B (ushort)0x0048
1565#define ASCV_DONENEXT_B (ushort)0x0049
1566#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
1567#define ASCV_SCSIBUSY_B (ushort)0x004B
1568#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
1569#define ASCV_CURCDB_B (ushort)0x004D
1570#define ASCV_RCLUN_B (ushort)0x004E
1571#define ASCV_BUSY_QHEAD_B (ushort)0x004F
1572#define ASCV_DISC1_QHEAD_B (ushort)0x0050
1573#define ASCV_DISC_ENABLE_B (ushort)0x0052
1574#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
1575#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
1576#define ASCV_MCODE_CNTL_B (ushort)0x0056
1577#define ASCV_NULL_TARGET_B (ushort)0x0057
1578#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
1579#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
1580#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
1581#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
1582#define ASCV_HOST_FLAG_B (ushort)0x005D
1583#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
1584#define ASCV_VER_SERIAL_B (ushort)0x0065
1585#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
1586#define ASCV_WTM_FLAG_B (ushort)0x0068
1587#define ASCV_RISC_FLAG_B (ushort)0x006A
1588#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
1589#define ASC_HOST_FLAG_IN_ISR 0x01
1590#define ASC_HOST_FLAG_ACK_INT 0x02
1591#define ASC_RISC_FLAG_GEN_INT 0x01
1592#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
1593#define IOP_CTRL (0x0F)
1594#define IOP_STATUS (0x0E)
1595#define IOP_INT_ACK IOP_STATUS
1596#define IOP_REG_IFC (0x0D)
1597#define IOP_SYN_OFFSET (0x0B)
1598#define IOP_EXTRA_CONTROL (0x0D)
1599#define IOP_REG_PC (0x0C)
1600#define IOP_RAM_ADDR (0x0A)
1601#define IOP_RAM_DATA (0x08)
1602#define IOP_EEP_DATA (0x06)
1603#define IOP_EEP_CMD (0x07)
1604#define IOP_VERSION (0x03)
1605#define IOP_CONFIG_HIGH (0x04)
1606#define IOP_CONFIG_LOW (0x02)
1607#define IOP_SIG_BYTE (0x01)
1608#define IOP_SIG_WORD (0x00)
1609#define IOP_REG_DC1 (0x0E)
1610#define IOP_REG_DC0 (0x0C)
1611#define IOP_REG_SB (0x0B)
1612#define IOP_REG_DA1 (0x0A)
1613#define IOP_REG_DA0 (0x08)
1614#define IOP_REG_SC (0x09)
1615#define IOP_DMA_SPEED (0x07)
1616#define IOP_REG_FLAG (0x07)
1617#define IOP_FIFO_H (0x06)
1618#define IOP_FIFO_L (0x04)
1619#define IOP_REG_ID (0x05)
1620#define IOP_REG_QP (0x03)
1621#define IOP_REG_IH (0x02)
1622#define IOP_REG_IX (0x01)
1623#define IOP_REG_AX (0x00)
1624#define IFC_REG_LOCK (0x00)
1625#define IFC_REG_UNLOCK (0x09)
1626#define IFC_WR_EN_FILTER (0x10)
1627#define IFC_RD_NO_EEPROM (0x10)
1628#define IFC_SLEW_RATE (0x20)
1629#define IFC_ACT_NEG (0x40)
1630#define IFC_INP_FILTER (0x80)
1631#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
1632#define SC_SEL (uchar)(0x80)
1633#define SC_BSY (uchar)(0x40)
1634#define SC_ACK (uchar)(0x20)
1635#define SC_REQ (uchar)(0x10)
1636#define SC_ATN (uchar)(0x08)
1637#define SC_IO (uchar)(0x04)
1638#define SC_CD (uchar)(0x02)
1639#define SC_MSG (uchar)(0x01)
1640#define SEC_SCSI_CTL (uchar)(0x80)
1641#define SEC_ACTIVE_NEGATE (uchar)(0x40)
1642#define SEC_SLEW_RATE (uchar)(0x20)
1643#define SEC_ENABLE_FILTER (uchar)(0x10)
1644#define ASC_HALT_EXTMSG_IN (ushort)0x8000
1645#define ASC_HALT_CHK_CONDITION (ushort)0x8100
1646#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
1647#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
1648#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
1649#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
1650#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
1651#define ASC_MAX_QNO 0xF8
1652#define ASC_DATA_SEC_BEG (ushort)0x0080
1653#define ASC_DATA_SEC_END (ushort)0x0080
1654#define ASC_CODE_SEC_BEG (ushort)0x0080
1655#define ASC_CODE_SEC_END (ushort)0x0080
1656#define ASC_QADR_BEG (0x4000)
1657#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
1658#define ASC_QADR_END (ushort)0x7FFF
1659#define ASC_QLAST_ADR (ushort)0x7FC0
1660#define ASC_QBLK_SIZE 0x40
1661#define ASC_BIOS_DATA_QBEG 0xF8
1662#define ASC_MIN_ACTIVE_QNO 0x01
1663#define ASC_QLINK_END 0xFF
1664#define ASC_EEPROM_WORDS 0x10
1665#define ASC_MAX_MGS_LEN 0x10
1666#define ASC_BIOS_ADDR_DEF 0xDC00
1667#define ASC_BIOS_SIZE 0x3800
1668#define ASC_BIOS_RAM_OFF 0x3800
1669#define ASC_BIOS_RAM_SIZE 0x800
1670#define ASC_BIOS_MIN_ADDR 0xC000
1671#define ASC_BIOS_MAX_ADDR 0xEC00
1672#define ASC_BIOS_BANK_SIZE 0x0400
1673#define ASC_MCODE_START_ADDR 0x0080
1674#define ASC_CFG0_HOST_INT_ON 0x0020
1675#define ASC_CFG0_BIOS_ON 0x0040
1676#define ASC_CFG0_VERA_BURST_ON 0x0080
1677#define ASC_CFG0_SCSI_PARITY_ON 0x0800
1678#define ASC_CFG1_SCSI_TARGET_ON 0x0080
1679#define ASC_CFG1_LRAM_8BITS_ON 0x0800
1680#define ASC_CFG_MSW_CLR_MASK 0x3080
1681#define CSW_TEST1 (ASC_CS_TYPE)0x8000
1682#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
1683#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
1684#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
1685#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
1686#define CSW_TEST2 (ASC_CS_TYPE)0x0400
1687#define CSW_TEST3 (ASC_CS_TYPE)0x0200
1688#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
1689#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
1690#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
1691#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
1692#define CSW_HALTED (ASC_CS_TYPE)0x0010
1693#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
1694#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
1695#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
1696#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
1697#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
1698#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
1699#define CIW_TEST1 (ASC_CS_TYPE)0x0200
1700#define CIW_TEST2 (ASC_CS_TYPE)0x0400
1701#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
1702#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
1703#define CC_CHIP_RESET (uchar)0x80
1704#define CC_SCSI_RESET (uchar)0x40
1705#define CC_HALT (uchar)0x20
1706#define CC_SINGLE_STEP (uchar)0x10
1707#define CC_DMA_ABLE (uchar)0x08
1708#define CC_TEST (uchar)0x04
1709#define CC_BANK_ONE (uchar)0x02
1710#define CC_DIAG (uchar)0x01
1711#define ASC_1000_ID0W 0x04C1
1712#define ASC_1000_ID0W_FIX 0x00C1
1713#define ASC_1000_ID1B 0x25
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714#define ASC_EISA_REV_IOP_MASK (0x0C83)
1715#define ASC_EISA_PID_IOP_MASK (0x0C80)
1716#define ASC_EISA_CFG_IOP_MASK (0x0C86)
1717#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718#define INS_HALTINT (ushort)0x6281
1719#define INS_HALT (ushort)0x6280
1720#define INS_SINT (ushort)0x6200
1721#define INS_RFLAG_WTM (ushort)0x7380
1722#define ASC_MC_SAVE_CODE_WSIZE 0x500
1723#define ASC_MC_SAVE_DATA_WSIZE 0x40
1724
1725typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001726 ushort data[ASC_MC_SAVE_DATA_WSIZE];
1727 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728} ASC_MC_SAVED;
1729
1730#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
1731#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
1732#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
1733#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
1734#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
1735#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
1736#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
1737#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
1738#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
1739#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
1740#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
1741#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
1742#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
1743#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
1744#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
1745#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
1746#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
1747#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
1748#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
1749#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
1750#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
1751#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
1752#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
1753#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
1754#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
1755#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
1756#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
1757#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
1758#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
1759#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
1760#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
1761#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
1762#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
1763#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
1764#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
1765#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
1766#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
1767#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
1768#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
1769#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
1770#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
1771#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
1772#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
1773#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
1774#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
1775#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
1776#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
1777#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
1778#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
1779#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
1780#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
1781#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
1782#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
1783#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
1784#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
1785#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
1786#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
1787#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
1788#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
1789#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
1790#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
1791#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
1792#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
1793#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
1794#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
1795#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
1796#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
1797#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
1798
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001799static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
1800static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
1801static void AscWaitEEPRead(void);
1802static void AscWaitEEPWrite(void);
1803static ushort AscReadEEPWord(PortAddr, uchar);
1804static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
1805static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1806static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
1807static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1808static int AscStartChip(PortAddr);
1809static int AscStopChip(PortAddr);
1810static void AscSetChipIH(PortAddr, ushort);
1811static int AscIsChipHalted(PortAddr);
1812static void AscAckInterrupt(PortAddr);
1813static void AscDisableInterrupt(PortAddr);
1814static void AscEnableInterrupt(PortAddr);
1815static void AscSetBank(PortAddr, uchar);
1816static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001818static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001820static uchar AscReadLramByte(PortAddr, ushort);
1821static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001823static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001825static void AscWriteLramWord(PortAddr, ushort, ushort);
1826static void AscWriteLramByte(PortAddr, ushort, uchar);
1827static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
1828static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
1829static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1830static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1831static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
1832static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
1833static ushort AscInitFromEEP(ASC_DVC_VAR *);
1834static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
1835static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1836static int AscTestExternalLram(ASC_DVC_VAR *);
1837static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1838static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1839static void AscSetChipSDTR(PortAddr, uchar, uchar);
1840static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1841static uchar AscAllocFreeQueue(PortAddr, uchar);
1842static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1843static int AscHostReqRiscHalt(PortAddr);
1844static int AscStopQueueExe(PortAddr);
1845static int AscSendScsiQueue(ASC_DVC_VAR *,
1846 ASC_SCSI_Q *scsiq, uchar n_q_required);
1847static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1848static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1849static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1850static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1851static ushort AscInitLram(ASC_DVC_VAR *);
1852static ushort AscInitQLinkVar(ASC_DVC_VAR *);
1853static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1854static int AscIsrChipHalted(ASC_DVC_VAR *);
1855static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1856 ASC_QDONE_INFO *, ASC_DCNT);
1857static int AscIsrQDone(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001859static ushort AscGetEisaChipCfg(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001861static uchar AscGetChipScsiCtrl(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001862static uchar AscGetChipVersion(PortAddr, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001863static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001864static void AscToggleIRQAct(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001865static inline ulong DvcEnterCritical(void);
1866static inline void DvcLeaveCritical(ulong);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001867static void DvcSleepMilliSecond(ASC_DCNT);
1868static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
1869static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1870static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001871static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04001872static void AscAsyncFix(ASC_DVC_VAR *, struct scsi_device *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001873static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1874static int AscISR(ASC_DVC_VAR *);
1875static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1876static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001878static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001880static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
1882/*
1883 * --- Adv Library Constants and Macros
1884 */
1885
1886#define ADV_LIB_VERSION_MAJOR 5
1887#define ADV_LIB_VERSION_MINOR 14
1888
1889/*
1890 * Define Adv Library required special types.
1891 */
1892
1893/*
1894 * Portable Data Types
1895 *
1896 * Any instance where a 32-bit long or pointer type is assumed
1897 * for precision or HW defined structures, the following define
1898 * types must be used. In Linux the char, short, and int types
1899 * are all consistent at 8, 16, and 32 bits respectively. Pointers
1900 * and long types are 64 bits on Alpha and UltraSPARC.
1901 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001902#define ADV_PADDR __u32 /* Physical address data type. */
1903#define ADV_VADDR __u32 /* Virtual address data type. */
1904#define ADV_DCNT __u32 /* Unsigned Data count type. */
1905#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906
1907/*
1908 * These macros are used to convert a virtual address to a
1909 * 32-bit value. This currently can be used on Linux Alpha
1910 * which uses 64-bit virtual address but a 32-bit bus address.
1911 * This is likely to break in the future, but doing this now
1912 * will give us time to change the HW and FW to handle 64-bit
1913 * addresses.
1914 */
1915#define ADV_VADDR_TO_U32 virt_to_bus
1916#define ADV_U32_TO_VADDR bus_to_virt
1917
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001918#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919
1920/*
1921 * Define Adv Library required memory access macros.
1922 */
1923#define ADV_MEM_READB(addr) readb(addr)
1924#define ADV_MEM_READW(addr) readw(addr)
1925#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
1926#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
1927#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
1928
1929#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
1930
1931/*
1932 * For wide boards a CDB length maximum of 16 bytes
1933 * is supported.
1934 */
1935#define ADV_MAX_CDB_LEN 16
1936
1937/*
1938 * Define total number of simultaneous maximum element scatter-gather
1939 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
1940 * maximum number of outstanding commands per wide host adapter. Each
1941 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
1942 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
1943 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
1944 * structures or 255 scatter-gather elements.
1945 *
1946 */
1947#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
1948
1949/*
1950 * Define Adv Library required maximum number of scatter-gather
1951 * elements per request.
1952 */
1953#define ADV_MAX_SG_LIST 255
1954
1955/* Number of SG blocks needed. */
1956#define ADV_NUM_SG_BLOCK \
1957 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
1958
1959/* Total contiguous memory needed for SG blocks. */
1960#define ADV_SG_TOTAL_MEM_SIZE \
1961 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
1962
1963#define ADV_PAGE_SIZE PAGE_SIZE
1964
1965#define ADV_NUM_PAGE_CROSSING \
1966 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
1967
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968#define ADV_EEP_DVC_CFG_BEGIN (0x00)
1969#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001970#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971#define ADV_EEP_MAX_WORD_ADDR (0x1E)
1972
1973#define ADV_EEP_DELAY_MS 100
1974
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001975#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
1976#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977/*
1978 * For the ASC3550 Bit 13 is Termination Polarity control bit.
1979 * For later ICs Bit 13 controls whether the CIS (Card Information
1980 * Service Section) is loaded from EEPROM.
1981 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001982#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
1983#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984/*
1985 * ASC38C1600 Bit 11
1986 *
1987 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
1988 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
1989 * Function 0 will specify INT B.
1990 *
1991 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
1992 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
1993 * Function 1 will specify INT A.
1994 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001995#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001997typedef struct adveep_3550_config {
1998 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002000 ushort cfg_lsw; /* 00 power up initialization */
2001 /* bit 13 set - Term Polarity Control */
2002 /* bit 14 set - BIOS Enable */
2003 /* bit 15 set - Big Endian Mode */
2004 ushort cfg_msw; /* 01 unused */
2005 ushort disc_enable; /* 02 disconnect enable */
2006 ushort wdtr_able; /* 03 Wide DTR able */
2007 ushort sdtr_able; /* 04 Synchronous DTR able */
2008 ushort start_motor; /* 05 send start up motor */
2009 ushort tagqng_able; /* 06 tag queuing able */
2010 ushort bios_scan; /* 07 BIOS device control */
2011 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002013 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2014 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002016 uchar scsi_reset_delay; /* 10 reset delay */
2017 uchar bios_id_lun; /* first boot device scsi id & lun */
2018 /* high nibble is lun */
2019 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002021 uchar termination; /* 11 0 - automatic */
2022 /* 1 - low off / high off */
2023 /* 2 - low off / high on */
2024 /* 3 - low on / high on */
2025 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002027 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002029 ushort bios_ctrl; /* 12 BIOS control bits */
2030 /* bit 0 BIOS don't act as initiator. */
2031 /* bit 1 BIOS > 1 GB support */
2032 /* bit 2 BIOS > 2 Disk Support */
2033 /* bit 3 BIOS don't support removables */
2034 /* bit 4 BIOS support bootable CD */
2035 /* bit 5 BIOS scan enabled */
2036 /* bit 6 BIOS support multiple LUNs */
2037 /* bit 7 BIOS display of message */
2038 /* bit 8 SCAM disabled */
2039 /* bit 9 Reset SCSI bus during init. */
2040 /* bit 10 */
2041 /* bit 11 No verbose initialization. */
2042 /* bit 12 SCSI parity enabled */
2043 /* bit 13 */
2044 /* bit 14 */
2045 /* bit 15 */
2046 ushort ultra_able; /* 13 ULTRA speed able */
2047 ushort reserved2; /* 14 reserved */
2048 uchar max_host_qng; /* 15 maximum host queuing */
2049 uchar max_dvc_qng; /* maximum per device queuing */
2050 ushort dvc_cntl; /* 16 control bit for driver */
2051 ushort bug_fix; /* 17 control bit for bug fix */
2052 ushort serial_number_word1; /* 18 Board serial number word 1 */
2053 ushort serial_number_word2; /* 19 Board serial number word 2 */
2054 ushort serial_number_word3; /* 20 Board serial number word 3 */
2055 ushort check_sum; /* 21 EEP check sum */
2056 uchar oem_name[16]; /* 22 OEM name */
2057 ushort dvc_err_code; /* 30 last device driver error code */
2058 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2059 ushort adv_err_addr; /* 32 last uc error address */
2060 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2061 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2062 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2063 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064} ADVEEP_3550_CONFIG;
2065
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002066typedef struct adveep_38C0800_config {
2067 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002069 ushort cfg_lsw; /* 00 power up initialization */
2070 /* bit 13 set - Load CIS */
2071 /* bit 14 set - BIOS Enable */
2072 /* bit 15 set - Big Endian Mode */
2073 ushort cfg_msw; /* 01 unused */
2074 ushort disc_enable; /* 02 disconnect enable */
2075 ushort wdtr_able; /* 03 Wide DTR able */
2076 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2077 ushort start_motor; /* 05 send start up motor */
2078 ushort tagqng_able; /* 06 tag queuing able */
2079 ushort bios_scan; /* 07 BIOS device control */
2080 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002082 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2083 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002085 uchar scsi_reset_delay; /* 10 reset delay */
2086 uchar bios_id_lun; /* first boot device scsi id & lun */
2087 /* high nibble is lun */
2088 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002090 uchar termination_se; /* 11 0 - automatic */
2091 /* 1 - low off / high off */
2092 /* 2 - low off / high on */
2093 /* 3 - low on / high on */
2094 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002096 uchar termination_lvd; /* 11 0 - automatic */
2097 /* 1 - low off / high off */
2098 /* 2 - low off / high on */
2099 /* 3 - low on / high on */
2100 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002102 ushort bios_ctrl; /* 12 BIOS control bits */
2103 /* bit 0 BIOS don't act as initiator. */
2104 /* bit 1 BIOS > 1 GB support */
2105 /* bit 2 BIOS > 2 Disk Support */
2106 /* bit 3 BIOS don't support removables */
2107 /* bit 4 BIOS support bootable CD */
2108 /* bit 5 BIOS scan enabled */
2109 /* bit 6 BIOS support multiple LUNs */
2110 /* bit 7 BIOS display of message */
2111 /* bit 8 SCAM disabled */
2112 /* bit 9 Reset SCSI bus during init. */
2113 /* bit 10 */
2114 /* bit 11 No verbose initialization. */
2115 /* bit 12 SCSI parity enabled */
2116 /* bit 13 */
2117 /* bit 14 */
2118 /* bit 15 */
2119 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2120 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2121 uchar max_host_qng; /* 15 maximum host queueing */
2122 uchar max_dvc_qng; /* maximum per device queuing */
2123 ushort dvc_cntl; /* 16 control bit for driver */
2124 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2125 ushort serial_number_word1; /* 18 Board serial number word 1 */
2126 ushort serial_number_word2; /* 19 Board serial number word 2 */
2127 ushort serial_number_word3; /* 20 Board serial number word 3 */
2128 ushort check_sum; /* 21 EEP check sum */
2129 uchar oem_name[16]; /* 22 OEM name */
2130 ushort dvc_err_code; /* 30 last device driver error code */
2131 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2132 ushort adv_err_addr; /* 32 last uc error address */
2133 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2134 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2135 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2136 ushort reserved36; /* 36 reserved */
2137 ushort reserved37; /* 37 reserved */
2138 ushort reserved38; /* 38 reserved */
2139 ushort reserved39; /* 39 reserved */
2140 ushort reserved40; /* 40 reserved */
2141 ushort reserved41; /* 41 reserved */
2142 ushort reserved42; /* 42 reserved */
2143 ushort reserved43; /* 43 reserved */
2144 ushort reserved44; /* 44 reserved */
2145 ushort reserved45; /* 45 reserved */
2146 ushort reserved46; /* 46 reserved */
2147 ushort reserved47; /* 47 reserved */
2148 ushort reserved48; /* 48 reserved */
2149 ushort reserved49; /* 49 reserved */
2150 ushort reserved50; /* 50 reserved */
2151 ushort reserved51; /* 51 reserved */
2152 ushort reserved52; /* 52 reserved */
2153 ushort reserved53; /* 53 reserved */
2154 ushort reserved54; /* 54 reserved */
2155 ushort reserved55; /* 55 reserved */
2156 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2157 ushort cisprt_msw; /* 57 CIS PTR MSW */
2158 ushort subsysvid; /* 58 SubSystem Vendor ID */
2159 ushort subsysid; /* 59 SubSystem ID */
2160 ushort reserved60; /* 60 reserved */
2161 ushort reserved61; /* 61 reserved */
2162 ushort reserved62; /* 62 reserved */
2163 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164} ADVEEP_38C0800_CONFIG;
2165
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002166typedef struct adveep_38C1600_config {
2167 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002169 ushort cfg_lsw; /* 00 power up initialization */
2170 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
2171 /* clear - Func. 0 INTA, Func. 1 INTB */
2172 /* bit 13 set - Load CIS */
2173 /* bit 14 set - BIOS Enable */
2174 /* bit 15 set - Big Endian Mode */
2175 ushort cfg_msw; /* 01 unused */
2176 ushort disc_enable; /* 02 disconnect enable */
2177 ushort wdtr_able; /* 03 Wide DTR able */
2178 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2179 ushort start_motor; /* 05 send start up motor */
2180 ushort tagqng_able; /* 06 tag queuing able */
2181 ushort bios_scan; /* 07 BIOS device control */
2182 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002184 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2185 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002187 uchar scsi_reset_delay; /* 10 reset delay */
2188 uchar bios_id_lun; /* first boot device scsi id & lun */
2189 /* high nibble is lun */
2190 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002192 uchar termination_se; /* 11 0 - automatic */
2193 /* 1 - low off / high off */
2194 /* 2 - low off / high on */
2195 /* 3 - low on / high on */
2196 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002198 uchar termination_lvd; /* 11 0 - automatic */
2199 /* 1 - low off / high off */
2200 /* 2 - low off / high on */
2201 /* 3 - low on / high on */
2202 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002204 ushort bios_ctrl; /* 12 BIOS control bits */
2205 /* bit 0 BIOS don't act as initiator. */
2206 /* bit 1 BIOS > 1 GB support */
2207 /* bit 2 BIOS > 2 Disk Support */
2208 /* bit 3 BIOS don't support removables */
2209 /* bit 4 BIOS support bootable CD */
2210 /* bit 5 BIOS scan enabled */
2211 /* bit 6 BIOS support multiple LUNs */
2212 /* bit 7 BIOS display of message */
2213 /* bit 8 SCAM disabled */
2214 /* bit 9 Reset SCSI bus during init. */
2215 /* bit 10 Basic Integrity Checking disabled */
2216 /* bit 11 No verbose initialization. */
2217 /* bit 12 SCSI parity enabled */
2218 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
2219 /* bit 14 */
2220 /* bit 15 */
2221 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2222 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2223 uchar max_host_qng; /* 15 maximum host queueing */
2224 uchar max_dvc_qng; /* maximum per device queuing */
2225 ushort dvc_cntl; /* 16 control bit for driver */
2226 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2227 ushort serial_number_word1; /* 18 Board serial number word 1 */
2228 ushort serial_number_word2; /* 19 Board serial number word 2 */
2229 ushort serial_number_word3; /* 20 Board serial number word 3 */
2230 ushort check_sum; /* 21 EEP check sum */
2231 uchar oem_name[16]; /* 22 OEM name */
2232 ushort dvc_err_code; /* 30 last device driver error code */
2233 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2234 ushort adv_err_addr; /* 32 last uc error address */
2235 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2236 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2237 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2238 ushort reserved36; /* 36 reserved */
2239 ushort reserved37; /* 37 reserved */
2240 ushort reserved38; /* 38 reserved */
2241 ushort reserved39; /* 39 reserved */
2242 ushort reserved40; /* 40 reserved */
2243 ushort reserved41; /* 41 reserved */
2244 ushort reserved42; /* 42 reserved */
2245 ushort reserved43; /* 43 reserved */
2246 ushort reserved44; /* 44 reserved */
2247 ushort reserved45; /* 45 reserved */
2248 ushort reserved46; /* 46 reserved */
2249 ushort reserved47; /* 47 reserved */
2250 ushort reserved48; /* 48 reserved */
2251 ushort reserved49; /* 49 reserved */
2252 ushort reserved50; /* 50 reserved */
2253 ushort reserved51; /* 51 reserved */
2254 ushort reserved52; /* 52 reserved */
2255 ushort reserved53; /* 53 reserved */
2256 ushort reserved54; /* 54 reserved */
2257 ushort reserved55; /* 55 reserved */
2258 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2259 ushort cisprt_msw; /* 57 CIS PTR MSW */
2260 ushort subsysvid; /* 58 SubSystem Vendor ID */
2261 ushort subsysid; /* 59 SubSystem ID */
2262 ushort reserved60; /* 60 reserved */
2263 ushort reserved61; /* 61 reserved */
2264 ushort reserved62; /* 62 reserved */
2265 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266} ADVEEP_38C1600_CONFIG;
2267
2268/*
2269 * EEPROM Commands
2270 */
2271#define ASC_EEP_CMD_DONE 0x0200
2272#define ASC_EEP_CMD_DONE_ERR 0x0001
2273
2274/* cfg_word */
2275#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
2276
2277/* bios_ctrl */
2278#define BIOS_CTRL_BIOS 0x0001
2279#define BIOS_CTRL_EXTENDED_XLAT 0x0002
2280#define BIOS_CTRL_GT_2_DISK 0x0004
2281#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
2282#define BIOS_CTRL_BOOTABLE_CD 0x0010
2283#define BIOS_CTRL_MULTIPLE_LUN 0x0040
2284#define BIOS_CTRL_DISPLAY_MSG 0x0080
2285#define BIOS_CTRL_NO_SCAM 0x0100
2286#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
2287#define BIOS_CTRL_INIT_VERBOSE 0x0800
2288#define BIOS_CTRL_SCSI_PARITY 0x1000
2289#define BIOS_CTRL_AIPP_DIS 0x2000
2290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002291#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002293#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
2295/*
2296 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
2297 * a special 16K Adv Library and Microcode version. After the issue is
2298 * resolved, should restore 32K support.
2299 *
2300 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
2301 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002302#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303
2304/*
2305 * Byte I/O register address from base of 'iop_base'.
2306 */
2307#define IOPB_INTR_STATUS_REG 0x00
2308#define IOPB_CHIP_ID_1 0x01
2309#define IOPB_INTR_ENABLES 0x02
2310#define IOPB_CHIP_TYPE_REV 0x03
2311#define IOPB_RES_ADDR_4 0x04
2312#define IOPB_RES_ADDR_5 0x05
2313#define IOPB_RAM_DATA 0x06
2314#define IOPB_RES_ADDR_7 0x07
2315#define IOPB_FLAG_REG 0x08
2316#define IOPB_RES_ADDR_9 0x09
2317#define IOPB_RISC_CSR 0x0A
2318#define IOPB_RES_ADDR_B 0x0B
2319#define IOPB_RES_ADDR_C 0x0C
2320#define IOPB_RES_ADDR_D 0x0D
2321#define IOPB_SOFT_OVER_WR 0x0E
2322#define IOPB_RES_ADDR_F 0x0F
2323#define IOPB_MEM_CFG 0x10
2324#define IOPB_RES_ADDR_11 0x11
2325#define IOPB_GPIO_DATA 0x12
2326#define IOPB_RES_ADDR_13 0x13
2327#define IOPB_FLASH_PAGE 0x14
2328#define IOPB_RES_ADDR_15 0x15
2329#define IOPB_GPIO_CNTL 0x16
2330#define IOPB_RES_ADDR_17 0x17
2331#define IOPB_FLASH_DATA 0x18
2332#define IOPB_RES_ADDR_19 0x19
2333#define IOPB_RES_ADDR_1A 0x1A
2334#define IOPB_RES_ADDR_1B 0x1B
2335#define IOPB_RES_ADDR_1C 0x1C
2336#define IOPB_RES_ADDR_1D 0x1D
2337#define IOPB_RES_ADDR_1E 0x1E
2338#define IOPB_RES_ADDR_1F 0x1F
2339#define IOPB_DMA_CFG0 0x20
2340#define IOPB_DMA_CFG1 0x21
2341#define IOPB_TICKLE 0x22
2342#define IOPB_DMA_REG_WR 0x23
2343#define IOPB_SDMA_STATUS 0x24
2344#define IOPB_SCSI_BYTE_CNT 0x25
2345#define IOPB_HOST_BYTE_CNT 0x26
2346#define IOPB_BYTE_LEFT_TO_XFER 0x27
2347#define IOPB_BYTE_TO_XFER_0 0x28
2348#define IOPB_BYTE_TO_XFER_1 0x29
2349#define IOPB_BYTE_TO_XFER_2 0x2A
2350#define IOPB_BYTE_TO_XFER_3 0x2B
2351#define IOPB_ACC_GRP 0x2C
2352#define IOPB_RES_ADDR_2D 0x2D
2353#define IOPB_DEV_ID 0x2E
2354#define IOPB_RES_ADDR_2F 0x2F
2355#define IOPB_SCSI_DATA 0x30
2356#define IOPB_RES_ADDR_31 0x31
2357#define IOPB_RES_ADDR_32 0x32
2358#define IOPB_SCSI_DATA_HSHK 0x33
2359#define IOPB_SCSI_CTRL 0x34
2360#define IOPB_RES_ADDR_35 0x35
2361#define IOPB_RES_ADDR_36 0x36
2362#define IOPB_RES_ADDR_37 0x37
2363#define IOPB_RAM_BIST 0x38
2364#define IOPB_PLL_TEST 0x39
2365#define IOPB_PCI_INT_CFG 0x3A
2366#define IOPB_RES_ADDR_3B 0x3B
2367#define IOPB_RFIFO_CNT 0x3C
2368#define IOPB_RES_ADDR_3D 0x3D
2369#define IOPB_RES_ADDR_3E 0x3E
2370#define IOPB_RES_ADDR_3F 0x3F
2371
2372/*
2373 * Word I/O register address from base of 'iop_base'.
2374 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002375#define IOPW_CHIP_ID_0 0x00 /* CID0 */
2376#define IOPW_CTRL_REG 0x02 /* CC */
2377#define IOPW_RAM_ADDR 0x04 /* LA */
2378#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002380#define IOPW_RISC_CSR 0x0A /* CSR */
2381#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
2382#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002384#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002386#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002388#define IOPW_EE_CMD 0x1A /* EC */
2389#define IOPW_EE_DATA 0x1C /* ED */
2390#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002392#define IOPW_Q_BASE 0x22 /* QB */
2393#define IOPW_QP 0x24 /* QP */
2394#define IOPW_IX 0x26 /* IX */
2395#define IOPW_SP 0x28 /* SP */
2396#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397#define IOPW_RES_ADDR_2C 0x2C
2398#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002399#define IOPW_SCSI_DATA 0x30 /* SD */
2400#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
2401#define IOPW_SCSI_CTRL 0x34 /* SC */
2402#define IOPW_HSHK_CFG 0x36 /* HCFG */
2403#define IOPW_SXFR_STATUS 0x36 /* SXS */
2404#define IOPW_SXFR_CNTL 0x38 /* SXL */
2405#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002407#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
2409/*
2410 * Doubleword I/O register address from base of 'iop_base'.
2411 */
2412#define IOPDW_RES_ADDR_0 0x00
2413#define IOPDW_RAM_DATA 0x04
2414#define IOPDW_RES_ADDR_8 0x08
2415#define IOPDW_RES_ADDR_C 0x0C
2416#define IOPDW_RES_ADDR_10 0x10
2417#define IOPDW_COMMA 0x14
2418#define IOPDW_COMMB 0x18
2419#define IOPDW_RES_ADDR_1C 0x1C
2420#define IOPDW_SDMA_ADDR0 0x20
2421#define IOPDW_SDMA_ADDR1 0x24
2422#define IOPDW_SDMA_COUNT 0x28
2423#define IOPDW_SDMA_ERROR 0x2C
2424#define IOPDW_RDMA_ADDR0 0x30
2425#define IOPDW_RDMA_ADDR1 0x34
2426#define IOPDW_RDMA_COUNT 0x38
2427#define IOPDW_RDMA_ERROR 0x3C
2428
2429#define ADV_CHIP_ID_BYTE 0x25
2430#define ADV_CHIP_ID_WORD 0x04C1
2431
2432#define ADV_SC_SCSI_BUS_RESET 0x2000
2433
2434#define ADV_INTR_ENABLE_HOST_INTR 0x01
2435#define ADV_INTR_ENABLE_SEL_INTR 0x02
2436#define ADV_INTR_ENABLE_DPR_INTR 0x04
2437#define ADV_INTR_ENABLE_RTA_INTR 0x08
2438#define ADV_INTR_ENABLE_RMA_INTR 0x10
2439#define ADV_INTR_ENABLE_RST_INTR 0x20
2440#define ADV_INTR_ENABLE_DPE_INTR 0x40
2441#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
2442
2443#define ADV_INTR_STATUS_INTRA 0x01
2444#define ADV_INTR_STATUS_INTRB 0x02
2445#define ADV_INTR_STATUS_INTRC 0x04
2446
2447#define ADV_RISC_CSR_STOP (0x0000)
2448#define ADV_RISC_TEST_COND (0x2000)
2449#define ADV_RISC_CSR_RUN (0x4000)
2450#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
2451
2452#define ADV_CTRL_REG_HOST_INTR 0x0100
2453#define ADV_CTRL_REG_SEL_INTR 0x0200
2454#define ADV_CTRL_REG_DPR_INTR 0x0400
2455#define ADV_CTRL_REG_RTA_INTR 0x0800
2456#define ADV_CTRL_REG_RMA_INTR 0x1000
2457#define ADV_CTRL_REG_RES_BIT14 0x2000
2458#define ADV_CTRL_REG_DPE_INTR 0x4000
2459#define ADV_CTRL_REG_POWER_DONE 0x8000
2460#define ADV_CTRL_REG_ANY_INTR 0xFF00
2461
2462#define ADV_CTRL_REG_CMD_RESET 0x00C6
2463#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
2464#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
2465#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
2466#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
2467
2468#define ADV_TICKLE_NOP 0x00
2469#define ADV_TICKLE_A 0x01
2470#define ADV_TICKLE_B 0x02
2471#define ADV_TICKLE_C 0x03
2472
2473#define ADV_SCSI_CTRL_RSTOUT 0x2000
2474
2475#define AdvIsIntPending(port) \
2476 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
2477
2478/*
2479 * SCSI_CFG0 Register bit definitions
2480 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002481#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
2482#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
2483#define EVEN_PARITY 0x1000 /* Select Even Parity */
2484#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
2485#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
2486#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
2487#define SCAM_EN 0x0080 /* Enable SCAM selection */
2488#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
2489#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
2490#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
2491#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492
2493/*
2494 * SCSI_CFG1 Register bit definitions
2495 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002496#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
2497#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
2498#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
2499#define FILTER_SEL 0x0C00 /* Filter Period Selection */
2500#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
2501#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
2502#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
2503#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
2504#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
2505#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
2506#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
2507#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
2508#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
2509#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
2510#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
2512/*
2513 * Addendum for ASC-38C0800 Chip
2514 *
2515 * The ASC-38C1600 Chip uses the same definitions except that the
2516 * bus mode override bits [12:10] have been moved to byte register
2517 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
2518 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
2519 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
2520 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
2521 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
2522 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002523#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
2524#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
2525#define HVD 0x1000 /* HVD Device Detect */
2526#define LVD 0x0800 /* LVD Device Detect */
2527#define SE 0x0400 /* SE Device Detect */
2528#define TERM_LVD 0x00C0 /* LVD Termination Bits */
2529#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
2530#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
2531#define TERM_SE 0x0030 /* SE Termination Bits */
2532#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
2533#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
2534#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
2535#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
2536#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
2537#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
2538#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
2539#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
2541#define CABLE_ILLEGAL_A 0x7
2542 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
2543
2544#define CABLE_ILLEGAL_B 0xB
2545 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
2546
2547/*
2548 * MEM_CFG Register bit definitions
2549 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002550#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
2551#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
2552#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
2553#define RAM_SZ_2KB 0x00 /* 2 KB */
2554#define RAM_SZ_4KB 0x04 /* 4 KB */
2555#define RAM_SZ_8KB 0x08 /* 8 KB */
2556#define RAM_SZ_16KB 0x0C /* 16 KB */
2557#define RAM_SZ_32KB 0x10 /* 32 KB */
2558#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559
2560/*
2561 * DMA_CFG0 Register bit definitions
2562 *
2563 * This register is only accessible to the host.
2564 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002565#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
2566#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
2567#define FIFO_THRESH_16B 0x00 /* 16 bytes */
2568#define FIFO_THRESH_32B 0x20 /* 32 bytes */
2569#define FIFO_THRESH_48B 0x30 /* 48 bytes */
2570#define FIFO_THRESH_64B 0x40 /* 64 bytes */
2571#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
2572#define FIFO_THRESH_96B 0x60 /* 96 bytes */
2573#define FIFO_THRESH_112B 0x70 /* 112 bytes */
2574#define START_CTL 0x0C /* DMA start conditions */
2575#define START_CTL_TH 0x00 /* Wait threshold level (default) */
2576#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
2577#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
2578#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
2579#define READ_CMD 0x03 /* Memory Read Method */
2580#define READ_CMD_MR 0x00 /* Memory Read */
2581#define READ_CMD_MRL 0x02 /* Memory Read Long */
2582#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584/*
2585 * ASC-38C0800 RAM BIST Register bit definitions
2586 */
2587#define RAM_TEST_MODE 0x80
2588#define PRE_TEST_MODE 0x40
2589#define NORMAL_MODE 0x00
2590#define RAM_TEST_DONE 0x10
2591#define RAM_TEST_STATUS 0x0F
2592#define RAM_TEST_HOST_ERROR 0x08
2593#define RAM_TEST_INTRAM_ERROR 0x04
2594#define RAM_TEST_RISC_ERROR 0x02
2595#define RAM_TEST_SCSI_ERROR 0x01
2596#define RAM_TEST_SUCCESS 0x00
2597#define PRE_TEST_VALUE 0x05
2598#define NORMAL_VALUE 0x00
2599
2600/*
2601 * ASC38C1600 Definitions
2602 *
2603 * IOPB_PCI_INT_CFG Bit Field Definitions
2604 */
2605
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002606#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
2608/*
2609 * Bit 1 can be set to change the interrupt for the Function to operate in
2610 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
2611 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
2612 * mode, otherwise the operating mode is undefined.
2613 */
2614#define TOTEMPOLE 0x02
2615
2616/*
2617 * Bit 0 can be used to change the Int Pin for the Function. The value is
2618 * 0 by default for both Functions with Function 0 using INT A and Function
2619 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
2620 * INT A is used.
2621 *
2622 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
2623 * value specified in the PCI Configuration Space.
2624 */
2625#define INTAB 0x01
2626
2627/* a_advlib.h */
2628
2629/*
2630 * Adv Library Status Definitions
2631 */
2632#define ADV_TRUE 1
2633#define ADV_FALSE 0
2634#define ADV_NOERROR 1
2635#define ADV_SUCCESS 1
2636#define ADV_BUSY 0
2637#define ADV_ERROR (-1)
2638
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639/*
2640 * ADV_DVC_VAR 'warn_code' values
2641 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002642#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
2643#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
2644#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
2645#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
2646#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002648#define ADV_MAX_TID 15 /* max. target identifier */
2649#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650
2651/*
2652 * Error code values are set in ADV_DVC_VAR 'err_code'.
2653 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002654#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
2655#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
2656#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
2657#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
2658#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
2659#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
2660#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
2661#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
2662#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
2663#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
2664#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
2665#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
2666#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
2667#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
2669/*
2670 * Fixed locations of microcode operating variables.
2671 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002672#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
2673#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
2674#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
2675#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
2676#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
2677#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
2678#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
2679#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
2680#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
2681#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
2682#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
2683#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
2684#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685#define ASC_MC_CHIP_TYPE 0x009A
2686#define ASC_MC_INTRB_CODE 0x009B
2687#define ASC_MC_WDTR_ABLE 0x009C
2688#define ASC_MC_SDTR_ABLE 0x009E
2689#define ASC_MC_TAGQNG_ABLE 0x00A0
2690#define ASC_MC_DISC_ENABLE 0x00A2
2691#define ASC_MC_IDLE_CMD_STATUS 0x00A4
2692#define ASC_MC_IDLE_CMD 0x00A6
2693#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
2694#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
2695#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
2696#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
2697#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
2698#define ASC_MC_SDTR_DONE 0x00B6
2699#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
2700#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
2701#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002702#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002704#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705#define ASC_MC_ICQ 0x0160
2706#define ASC_MC_IRQ 0x0164
2707#define ASC_MC_PPR_ABLE 0x017A
2708
2709/*
2710 * BIOS LRAM variable absolute offsets.
2711 */
2712#define BIOS_CODESEG 0x54
2713#define BIOS_CODELEN 0x56
2714#define BIOS_SIGNATURE 0x58
2715#define BIOS_VERSION 0x5A
2716
2717/*
2718 * Microcode Control Flags
2719 *
2720 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
2721 * and handled by the microcode.
2722 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002723#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
2724#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725
2726/*
2727 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
2728 */
2729#define HSHK_CFG_WIDE_XFR 0x8000
2730#define HSHK_CFG_RATE 0x0F00
2731#define HSHK_CFG_OFFSET 0x001F
2732
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002733#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
2734#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
2735#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
2736#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002738#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2739#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2740#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2741#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2742#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002744#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2745#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2746#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2747#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2748#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749/*
2750 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2751 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2752 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002753#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2754#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755
2756/*
2757 * All fields here are accessed by the board microcode and need to be
2758 * little-endian.
2759 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002760typedef struct adv_carr_t {
2761 ADV_VADDR carr_va; /* Carrier Virtual Address */
2762 ADV_PADDR carr_pa; /* Carrier Physical Address */
2763 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2764 /*
2765 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2766 *
2767 * next_vpa [3:1] Reserved Bits
2768 * next_vpa [0] Done Flag set in Response Queue.
2769 */
2770 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771} ADV_CARR_T;
2772
2773/*
2774 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2775 */
2776#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2777
2778#define ASC_RQ_DONE 0x00000001
2779#define ASC_RQ_GOOD 0x00000002
2780#define ASC_CQ_STOPPER 0x00000000
2781
2782#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2783
2784#define ADV_CARRIER_NUM_PAGE_CROSSING \
2785 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2786 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2787
2788#define ADV_CARRIER_BUFSIZE \
2789 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2790
2791/*
2792 * ASC_SCSI_REQ_Q 'a_flag' definitions
2793 *
2794 * The Adv Library should limit use to the lower nibble (4 bits) of
2795 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2796 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002797#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2798#define ADV_SCSIQ_DONE 0x02 /* request done */
2799#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002801#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2802#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2803#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
2805/*
2806 * Adapter temporary configuration structure
2807 *
2808 * This structure can be discarded after initialization. Don't add
2809 * fields here needed after initialization.
2810 *
2811 * Field naming convention:
2812 *
2813 * *_enable indicates the field enables or disables a feature. The
2814 * value of the field is never reset.
2815 */
2816typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002817 ushort disc_enable; /* enable disconnection */
2818 uchar chip_version; /* chip version */
2819 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2820 ushort lib_version; /* Adv Library version number */
2821 ushort control_flag; /* Microcode Control Flag */
2822 ushort mcode_date; /* Microcode date */
2823 ushort mcode_version; /* Microcode version */
2824 ushort pci_slot_info; /* high byte device/function number */
2825 /* bits 7-3 device num., bits 2-0 function num. */
2826 /* low byte bus num. */
2827 ushort serial1; /* EEPROM serial number word 1 */
2828 ushort serial2; /* EEPROM serial number word 2 */
2829 ushort serial3; /* EEPROM serial number word 3 */
2830 struct device *dev; /* pointer to the pci dev structure for this board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831} ADV_DVC_CFG;
2832
2833struct adv_dvc_var;
2834struct adv_scsi_req_q;
2835
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002836typedef void (*ADV_ISR_CALLBACK)
2837 (struct adv_dvc_var *, struct adv_scsi_req_q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002839typedef void (*ADV_ASYNC_CALLBACK)
2840 (struct adv_dvc_var *, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841
2842/*
2843 * Adapter operation variable structure.
2844 *
2845 * One structure is required per host adapter.
2846 *
2847 * Field naming convention:
2848 *
2849 * *_able indicates both whether a feature should be enabled or disabled
2850 * and whether a device isi capable of the feature. At initialization
2851 * this field may be set, but later if a device is found to be incapable
2852 * of the feature, the field is cleared.
2853 */
2854typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002855 AdvPortAddr iop_base; /* I/O port address */
2856 ushort err_code; /* fatal error code */
2857 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
2858 ADV_ISR_CALLBACK isr_callback;
2859 ADV_ASYNC_CALLBACK async_callback;
2860 ushort wdtr_able; /* try WDTR for a device */
2861 ushort sdtr_able; /* try SDTR for a device */
2862 ushort ultra_able; /* try SDTR Ultra speed for a device */
2863 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2864 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2865 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2866 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2867 ushort tagqng_able; /* try tagged queuing with a device */
2868 ushort ppr_able; /* PPR message capable per TID bitmask. */
2869 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2870 ushort start_motor; /* start motor command allowed */
2871 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2872 uchar chip_no; /* should be assigned by caller */
2873 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2874 uchar irq_no; /* IRQ number */
2875 ushort no_scam; /* scam_tolerant of EEPROM */
2876 struct asc_board *drv_ptr; /* driver pointer to private structure */
2877 uchar chip_scsi_id; /* chip SCSI target ID */
2878 uchar chip_type;
2879 uchar bist_err_code;
2880 ADV_CARR_T *carrier_buf;
2881 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2882 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2883 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2884 ushort carr_pending_cnt; /* Count of pending carriers. */
2885 /*
2886 * Note: The following fields will not be used after initialization. The
2887 * driver may discard the buffer after initialization is done.
2888 */
2889 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890} ADV_DVC_VAR;
2891
2892#define NO_OF_SG_PER_BLOCK 15
2893
2894typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002895 uchar reserved1;
2896 uchar reserved2;
2897 uchar reserved3;
2898 uchar sg_cnt; /* Valid entries in block. */
2899 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
2900 struct {
2901 ADV_PADDR sg_addr; /* SG element address. */
2902 ADV_DCNT sg_count; /* SG element count. */
2903 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904} ADV_SG_BLOCK;
2905
2906/*
2907 * ADV_SCSI_REQ_Q - microcode request structure
2908 *
2909 * All fields in this structure up to byte 60 are used by the microcode.
2910 * The microcode makes assumptions about the size and ordering of fields
2911 * in this structure. Do not change the structure definition here without
2912 * coordinating the change with the microcode.
2913 *
2914 * All fields accessed by microcode must be maintained in little_endian
2915 * order.
2916 */
2917typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002918 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
2919 uchar target_cmd;
2920 uchar target_id; /* Device target identifier. */
2921 uchar target_lun; /* Device target logical unit number. */
2922 ADV_PADDR data_addr; /* Data buffer physical address. */
2923 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
2924 ADV_PADDR sense_addr;
2925 ADV_PADDR carr_pa;
2926 uchar mflag;
2927 uchar sense_len;
2928 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
2929 uchar scsi_cntl;
2930 uchar done_status; /* Completion status. */
2931 uchar scsi_status; /* SCSI status byte. */
2932 uchar host_status; /* Ucode host status. */
2933 uchar sg_working_ix;
2934 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
2935 ADV_PADDR sg_real_addr; /* SG list physical address. */
2936 ADV_PADDR scsiq_rptr;
2937 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
2938 ADV_VADDR scsiq_ptr;
2939 ADV_VADDR carr_va;
2940 /*
2941 * End of microcode structure - 60 bytes. The rest of the structure
2942 * is used by the Adv Library and ignored by the microcode.
2943 */
2944 ADV_VADDR srb_ptr;
2945 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
2946 char *vdata_addr; /* Data buffer virtual address. */
2947 uchar a_flag;
2948 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949} ADV_SCSI_REQ_Q;
2950
2951/*
2952 * Microcode idle loop commands
2953 */
2954#define IDLE_CMD_COMPLETED 0
2955#define IDLE_CMD_STOP_CHIP 0x0001
2956#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
2957#define IDLE_CMD_SEND_INT 0x0004
2958#define IDLE_CMD_ABORT 0x0008
2959#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002960#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
2961#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962#define IDLE_CMD_SCSIREQ 0x0080
2963
2964#define IDLE_CMD_STATUS_SUCCESS 0x0001
2965#define IDLE_CMD_STATUS_FAILURE 0x0002
2966
2967/*
2968 * AdvSendIdleCmd() flag definitions.
2969 */
2970#define ADV_NOWAIT 0x01
2971
2972/*
2973 * Wait loop time out values.
2974 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002975#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
2976#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
2977#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
2978#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
2979#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002981#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
2982#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
2983#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
2984#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002986#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987
2988/*
2989 * Device drivers must define the following functions.
2990 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002991static inline ulong DvcEnterCritical(void);
2992static inline void DvcLeaveCritical(ulong);
2993static void DvcSleepMilliSecond(ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002994static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
2995 uchar *, ASC_SDCNT *, int);
2996static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997
2998/*
2999 * Adv Library functions available to drivers.
3000 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003001static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3002static int AdvISR(ADV_DVC_VAR *);
3003static int AdvInitGetConfig(ADV_DVC_VAR *);
3004static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
3005static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
3006static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
3007static int AdvResetChipAndSB(ADV_DVC_VAR *);
3008static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009
3010/*
3011 * Internal Adv Library functions.
3012 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003013static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003014static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
3015static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
3016static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
3017static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3018static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3019static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3020static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3021static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3022static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3023static void AdvWaitEEPCmd(AdvPortAddr);
3024static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026/* Read byte from a register. */
3027#define AdvReadByteRegister(iop_base, reg_off) \
3028 (ADV_MEM_READB((iop_base) + (reg_off)))
3029
3030/* Write byte to a register. */
3031#define AdvWriteByteRegister(iop_base, reg_off, byte) \
3032 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
3033
3034/* Read word (2 bytes) from a register. */
3035#define AdvReadWordRegister(iop_base, reg_off) \
3036 (ADV_MEM_READW((iop_base) + (reg_off)))
3037
3038/* Write word (2 bytes) to a register. */
3039#define AdvWriteWordRegister(iop_base, reg_off, word) \
3040 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
3041
3042/* Write dword (4 bytes) to a register. */
3043#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
3044 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
3045
3046/* Read byte from LRAM. */
3047#define AdvReadByteLram(iop_base, addr, byte) \
3048do { \
3049 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3050 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
3051} while (0)
3052
3053/* Write byte to LRAM. */
3054#define AdvWriteByteLram(iop_base, addr, byte) \
3055 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3056 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
3057
3058/* Read word (2 bytes) from LRAM. */
3059#define AdvReadWordLram(iop_base, addr, word) \
3060do { \
3061 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3062 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
3063} while (0)
3064
3065/* Write word (2 bytes) to LRAM. */
3066#define AdvWriteWordLram(iop_base, addr, word) \
3067 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3068 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3069
3070/* Write little-endian double word (4 bytes) to LRAM */
3071/* Because of unspecified C language ordering don't use auto-increment. */
3072#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
3073 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3074 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3075 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
3076 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
3077 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3078 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
3079
3080/* Read word (2 bytes) from LRAM assuming that the address is already set. */
3081#define AdvReadWordAutoIncLram(iop_base) \
3082 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
3083
3084/* Write word (2 bytes) to LRAM assuming that the address is already set. */
3085#define AdvWriteWordAutoIncLram(iop_base, word) \
3086 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3087
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088/*
3089 * Define macro to check for Condor signature.
3090 *
3091 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
3092 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
3093 */
3094#define AdvFindSignature(iop_base) \
3095 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
3096 ADV_CHIP_ID_BYTE) && \
3097 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
3098 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
3099
3100/*
3101 * Define macro to Return the version number of the chip at 'iop_base'.
3102 *
3103 * The second parameter 'bus_type' is currently unused.
3104 */
3105#define AdvGetChipVersion(iop_base, bus_type) \
3106 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
3107
3108/*
3109 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
3110 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
3111 *
3112 * If the request has not yet been sent to the device it will simply be
3113 * aborted from RISC memory. If the request is disconnected it will be
3114 * aborted on reselection by sending an Abort Message to the target ID.
3115 *
3116 * Return value:
3117 * ADV_TRUE(1) - Queue was successfully aborted.
3118 * ADV_FALSE(0) - Queue was not found on the active queue list.
3119 */
3120#define AdvAbortQueue(asc_dvc, scsiq) \
3121 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
3122 (ADV_DCNT) (scsiq))
3123
3124/*
3125 * Send a Bus Device Reset Message to the specified target ID.
3126 *
3127 * All outstanding commands will be purged if sending the
3128 * Bus Device Reset Message is successful.
3129 *
3130 * Return Value:
3131 * ADV_TRUE(1) - All requests on the target are purged.
3132 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
3133 * are not purged.
3134 */
3135#define AdvResetDevice(asc_dvc, target_id) \
3136 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
3137 (ADV_DCNT) (target_id))
3138
3139/*
3140 * SCSI Wide Type definition.
3141 */
3142#define ADV_SCSI_BIT_ID_TYPE ushort
3143
3144/*
3145 * AdvInitScsiTarget() 'cntl_flag' options.
3146 */
3147#define ADV_SCAN_LUN 0x01
3148#define ADV_CAPINFO_NOLUN 0x02
3149
3150/*
3151 * Convert target id to target id bit mask.
3152 */
3153#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
3154
3155/*
3156 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
3157 */
3158
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003159#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160#define QD_NO_ERROR 0x01
3161#define QD_ABORTED_BY_HOST 0x02
3162#define QD_WITH_ERROR 0x04
3163
3164#define QHSTA_NO_ERROR 0x00
3165#define QHSTA_M_SEL_TIMEOUT 0x11
3166#define QHSTA_M_DATA_OVER_RUN 0x12
3167#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
3168#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003169#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
3170#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
3171#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
3172#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
3173#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
3174#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
3175#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003177#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
3178#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
3179#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
3180#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
3181#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
3182#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
3183#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
3184#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185#define QHSTA_M_WTM_TIMEOUT 0x41
3186#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
3187#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
3188#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003189#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
3190#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
3191#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
3193/*
3194 * Default EEPROM Configuration structure defined in a_init.c.
3195 */
3196static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
3197static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
3198static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
3199
3200/*
3201 * DvcGetPhyAddr() flag arguments
3202 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003203#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
3204#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
3205#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
3206#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
3207#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
3208#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
3210/* Return the address that is aligned at the next doubleword >= to 'addr'. */
3211#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
3212#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
3213#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
3214
3215/*
3216 * Total contiguous memory needed for driver SG blocks.
3217 *
3218 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
3219 * number of scatter-gather elements the driver supports in a
3220 * single request.
3221 */
3222
3223#define ADV_SG_LIST_MAX_BYTE_SIZE \
3224 (sizeof(ADV_SG_BLOCK) * \
3225 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
3226
3227/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 * --- Driver Constants and Macros
3229 */
3230
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231/* Reference Scsi_Host hostdata */
3232#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
3233
3234/* asc_board_t flags */
3235#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003236#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237#define ASC_SELECT_QUEUE_DEPTHS 0x08
3238
3239#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
3240#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
3241
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003242#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003244#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245
3246#ifdef CONFIG_PROC_FS
3247/* /proc/scsi/advansys/[0...] related definitions */
3248#define ASC_PRTBUF_SIZE 2048
3249#define ASC_PRTLINE_SIZE 160
3250
3251#define ASC_PRT_NEXT() \
3252 if (cp) { \
3253 totlen += len; \
3254 leftlen -= len; \
3255 if (leftlen == 0) { \
3256 return totlen; \
3257 } \
3258 cp += len; \
3259 }
3260#endif /* CONFIG_PROC_FS */
3261
3262/* Asc Library return codes */
3263#define ASC_TRUE 1
3264#define ASC_FALSE 0
3265#define ASC_NOERROR 1
3266#define ASC_BUSY 0
3267#define ASC_ERROR (-1)
3268
3269/* struct scsi_cmnd function return codes */
3270#define STATUS_BYTE(byte) (byte)
3271#define MSG_BYTE(byte) ((byte) << 8)
3272#define HOST_BYTE(byte) ((byte) << 16)
3273#define DRIVER_BYTE(byte) ((byte) << 24)
3274
3275/*
3276 * The following definitions and macros are OS independent interfaces to
3277 * the queue functions:
3278 * REQ - SCSI request structure
3279 * REQP - pointer to SCSI request structure
3280 * REQPTID(reqp) - reqp's target id
3281 * REQPNEXT(reqp) - reqp's next pointer
3282 * REQPNEXTP(reqp) - pointer to reqp's next pointer
3283 * REQPTIME(reqp) - reqp's time stamp value
3284 * REQTIMESTAMP() - system time stamp value
3285 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003286typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
3288#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
3289#define REQPTID(reqp) ((reqp)->device->id)
3290#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
3291#define REQTIMESTAMP() (jiffies)
3292
3293#define REQTIMESTAT(function, ascq, reqp, tid) \
3294{ \
3295 /*
3296 * If the request time stamp is less than the system time stamp, then \
3297 * maybe the system time stamp wrapped. Set the request time to zero.\
3298 */ \
3299 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
3300 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
3301 } else { \
3302 /* Indicate an error occurred with the assertion. */ \
3303 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
3304 REQPTIME(reqp) = 0; \
3305 } \
3306 /* Handle first minimum time case without external initialization. */ \
3307 if (((ascq)->q_tot_cnt[tid] == 1) || \
3308 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
3309 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
3310 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
3311 (function), (tid), (ascq)->q_min_tim[tid]); \
3312 } \
3313 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
3314 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
3315 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
3316 (function), tid, (ascq)->q_max_tim[tid]); \
3317 } \
3318 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
3319 /* Reset the time stamp field. */ \
3320 REQPTIME(reqp) = 0; \
3321}
3322
3323/* asc_enqueue() flags */
3324#define ASC_FRONT 1
3325#define ASC_BACK 2
3326
3327/* asc_dequeue_list() argument */
3328#define ASC_TID_ALL (-1)
3329
3330/* Return non-zero, if the queue is empty. */
3331#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
3332
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003334#define ASC_STATS(shost, counter)
3335#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003337#define ASC_STATS(shost, counter) \
3338 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003340#define ASC_STATS_ADD(shost, counter, count) \
3341 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342#endif /* ADVANSYS_STATS */
3343
3344#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
3345
3346/* If the result wraps when calculating tenths, return 0. */
3347#define ASC_TENTHS(num, den) \
3348 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
3349 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
3350
3351/*
3352 * Display a message to the console.
3353 */
3354#define ASC_PRINT(s) \
3355 { \
3356 printk("advansys: "); \
3357 printk(s); \
3358 }
3359
3360#define ASC_PRINT1(s, a1) \
3361 { \
3362 printk("advansys: "); \
3363 printk((s), (a1)); \
3364 }
3365
3366#define ASC_PRINT2(s, a1, a2) \
3367 { \
3368 printk("advansys: "); \
3369 printk((s), (a1), (a2)); \
3370 }
3371
3372#define ASC_PRINT3(s, a1, a2, a3) \
3373 { \
3374 printk("advansys: "); \
3375 printk((s), (a1), (a2), (a3)); \
3376 }
3377
3378#define ASC_PRINT4(s, a1, a2, a3, a4) \
3379 { \
3380 printk("advansys: "); \
3381 printk((s), (a1), (a2), (a3), (a4)); \
3382 }
3383
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384#ifndef ADVANSYS_DEBUG
3385
3386#define ASC_DBG(lvl, s)
3387#define ASC_DBG1(lvl, s, a1)
3388#define ASC_DBG2(lvl, s, a1, a2)
3389#define ASC_DBG3(lvl, s, a1, a2, a3)
3390#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
3391#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
3392#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
3393#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
3394#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3395#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
3396#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3397#define ASC_DBG_PRT_HEX(lvl, name, start, length)
3398#define ASC_DBG_PRT_CDB(lvl, cdb, len)
3399#define ASC_DBG_PRT_SENSE(lvl, sense, len)
3400#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
3401
3402#else /* ADVANSYS_DEBUG */
3403
3404/*
3405 * Debugging Message Levels:
3406 * 0: Errors Only
3407 * 1: High-Level Tracing
3408 * 2-N: Verbose Tracing
3409 */
3410
3411#define ASC_DBG(lvl, s) \
3412 { \
3413 if (asc_dbglvl >= (lvl)) { \
3414 printk(s); \
3415 } \
3416 }
3417
3418#define ASC_DBG1(lvl, s, a1) \
3419 { \
3420 if (asc_dbglvl >= (lvl)) { \
3421 printk((s), (a1)); \
3422 } \
3423 }
3424
3425#define ASC_DBG2(lvl, s, a1, a2) \
3426 { \
3427 if (asc_dbglvl >= (lvl)) { \
3428 printk((s), (a1), (a2)); \
3429 } \
3430 }
3431
3432#define ASC_DBG3(lvl, s, a1, a2, a3) \
3433 { \
3434 if (asc_dbglvl >= (lvl)) { \
3435 printk((s), (a1), (a2), (a3)); \
3436 } \
3437 }
3438
3439#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
3440 { \
3441 if (asc_dbglvl >= (lvl)) { \
3442 printk((s), (a1), (a2), (a3), (a4)); \
3443 } \
3444 }
3445
3446#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
3447 { \
3448 if (asc_dbglvl >= (lvl)) { \
3449 asc_prt_scsi_host(s); \
3450 } \
3451 }
3452
3453#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
3454 { \
3455 if (asc_dbglvl >= (lvl)) { \
3456 asc_prt_scsi_cmnd(s); \
3457 } \
3458 }
3459
3460#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
3461 { \
3462 if (asc_dbglvl >= (lvl)) { \
3463 asc_prt_asc_scsi_q(scsiqp); \
3464 } \
3465 }
3466
3467#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
3468 { \
3469 if (asc_dbglvl >= (lvl)) { \
3470 asc_prt_asc_qdone_info(qdone); \
3471 } \
3472 }
3473
3474#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
3475 { \
3476 if (asc_dbglvl >= (lvl)) { \
3477 asc_prt_adv_scsi_req_q(scsiqp); \
3478 } \
3479 }
3480
3481#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
3482 { \
3483 if (asc_dbglvl >= (lvl)) { \
3484 asc_prt_hex((name), (start), (length)); \
3485 } \
3486 }
3487
3488#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
3489 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
3490
3491#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
3492 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
3493
3494#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
3495 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
3496#endif /* ADVANSYS_DEBUG */
3497
3498#ifndef ADVANSYS_ASSERT
3499#define ASC_ASSERT(a)
3500#else /* ADVANSYS_ASSERT */
3501
3502#define ASC_ASSERT(a) \
3503 { \
3504 if (!(a)) { \
3505 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
3506 __FILE__, __LINE__); \
3507 } \
3508 }
3509
3510#endif /* ADVANSYS_ASSERT */
3511
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512/*
3513 * --- Driver Structures
3514 */
3515
3516#ifdef ADVANSYS_STATS
3517
3518/* Per board statistics structure */
3519struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003520 /* Driver Entrypoint Statistics */
3521 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
3522 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
3523 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
3524 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
3525 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
3526 ADV_DCNT done; /* # calls to request's scsi_done function */
3527 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
3528 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
3529 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
3530 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
3531 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
3532 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
3533 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
3534 ADV_DCNT exe_unknown; /* # unknown returns. */
3535 /* Data Transfer Statistics */
3536 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
3537 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
3538 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
3539 ADV_DCNT sg_elem; /* # scatter-gather elements */
3540 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541};
3542#endif /* ADVANSYS_STATS */
3543
3544/*
3545 * Request queuing structure
3546 */
3547typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003548 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
3549 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
3550 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003552 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
3553 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
3554 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
3555 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
3556 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
3557 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
3558#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559} asc_queue_t;
3560
3561/*
3562 * Adv Library Request Structures
3563 *
3564 * The following two structures are used to process Wide Board requests.
3565 *
3566 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
3567 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
3568 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
3569 * Mid-Level SCSI request structure.
3570 *
3571 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
3572 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
3573 * up to 255 scatter-gather elements may be used per request or
3574 * ADV_SCSI_REQ_Q.
3575 *
3576 * Both structures must be 32 byte aligned.
3577 */
3578typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003579 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
3580 uchar align[32]; /* Sgblock structure padding. */
3581 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582} adv_sgblk_t;
3583
3584typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003585 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
3586 uchar align[32]; /* Request structure padding. */
3587 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
3588 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
3589 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590} adv_req_t;
3591
3592/*
3593 * Structure allocated for each board.
3594 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003595 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 * of the 'Scsi_Host' structure starting at the 'hostdata'
3597 * field. It is guaranteed to be allocated from DMA-able memory.
3598 */
3599typedef struct asc_board {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003600 int id; /* Board Id */
3601 uint flags; /* Board flags */
3602 union {
3603 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
3604 ADV_DVC_VAR adv_dvc_var; /* Wide board */
3605 } dvc_var;
3606 union {
3607 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
3608 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
3609 } dvc_cfg;
3610 ushort asc_n_io_port; /* Number I/O ports. */
3611 asc_queue_t active; /* Active command queue */
3612 asc_queue_t waiting; /* Waiting command queue */
3613 asc_queue_t done; /* Done command queue */
3614 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
3615 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
3616 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
3617 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
3618 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
3619 union {
3620 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
3621 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
3622 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
3623 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
3624 } eep_config;
3625 ulong last_reset; /* Saved last reset time */
3626 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003627 /* /proc/scsi/advansys/[0...] */
3628 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003630 struct asc_stats asc_stats; /* Board statistics */
3631#endif /* ADVANSYS_STATS */
3632 /*
3633 * The following fields are used only for Narrow Boards.
3634 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003635 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3636 /*
3637 * The following fields are used only for Wide Boards.
3638 */
3639 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3640 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06003641 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003642 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3643 adv_req_t *adv_reqp; /* Request structures. */
3644 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3645 ushort bios_signature; /* BIOS Signature. */
3646 ushort bios_version; /* BIOS Version. */
3647 ushort bios_codeseg; /* BIOS Code Segment. */
3648 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649} asc_board_t;
3650
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06003652static int asc_board_count;
3653
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003655static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656
3657/*
3658 * Global structures required to issue a command.
3659 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003660static ASC_SCSI_Q asc_scsi_q = { {0} };
3661static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003664static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665#endif /* ADVANSYS_DEBUG */
3666
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667/*
3668 * --- Driver Function Prototypes
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 */
3670
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003671static int advansys_slave_configure(struct scsi_device *);
3672static void asc_scsi_done_list(struct scsi_cmnd *);
3673static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3674static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3675static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3676static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
3677static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
3678static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3679static void adv_async_callback(ADV_DVC_VAR *, uchar);
3680static void asc_enqueue(asc_queue_t *, REQP, int);
3681static REQP asc_dequeue(asc_queue_t *, int);
3682static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3683static int asc_rmqueue(asc_queue_t *, REQP);
3684static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003686static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3687static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3688static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3689static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3690static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3691static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3692static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3693static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3694static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3695static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696#endif /* CONFIG_PROC_FS */
3697
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698/* Statistics function prototypes. */
3699#ifdef ADVANSYS_STATS
3700#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003701static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3702static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703#endif /* CONFIG_PROC_FS */
3704#endif /* ADVANSYS_STATS */
3705
3706/* Debug function prototypes. */
3707#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003708static void asc_prt_scsi_host(struct Scsi_Host *);
3709static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
3710static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
3711static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
3712static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
3713static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
3714static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
3715static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
3716static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
3717static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
3718static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719#endif /* ADVANSYS_DEBUG */
3720
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721#ifdef CONFIG_PROC_FS
3722/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06003723 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 *
3725 * *buffer: I/O buffer
3726 * **start: if inout == FALSE pointer into buffer where user read should start
3727 * offset: current offset into a /proc/scsi/advansys/[0...] file
3728 * length: length of buffer
3729 * hostno: Scsi_Host host_no
3730 * inout: TRUE - user is writing; FALSE - user is reading
3731 *
3732 * Return the number of bytes read from or written to a
3733 * /proc/scsi/advansys/[0...] file.
3734 *
3735 * Note: This function uses the per board buffer 'prtbuf' which is
3736 * allocated when the board is initialized in advansys_detect(). The
3737 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
3738 * used to write to the buffer. The way asc_proc_copy() is written
3739 * if 'prtbuf' is too small it will not be overwritten. Instead the
3740 * user just won't get all the available statistics.
3741 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003742static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003744 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003746 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003747 char *cp;
3748 int cplen;
3749 int cnt;
3750 int totcnt;
3751 int leftlen;
3752 char *curbuf;
3753 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003755 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756#endif /* ADVANSYS_STATS */
3757
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003758 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003760 /*
3761 * User write not supported.
3762 */
3763 if (inout == TRUE) {
3764 return (-ENOSYS);
3765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003767 /*
3768 * User read of /proc/scsi/advansys/[0...] file.
3769 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770
Matthew Wilcox2a437952007-07-26 11:00:51 -04003771 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003773 /* Copy read data starting at the beginning of the buffer. */
3774 *start = buffer;
3775 curbuf = buffer;
3776 advoffset = 0;
3777 totcnt = 0;
3778 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003780 /*
3781 * Get board configuration information.
3782 *
3783 * advansys_info() returns the board string from its own static buffer.
3784 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04003785 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003786 strcat(cp, "\n");
3787 cplen = strlen(cp);
3788 /* Copy board information. */
3789 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3790 totcnt += cnt;
3791 leftlen -= cnt;
3792 if (leftlen == 0) {
3793 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3794 return totcnt;
3795 }
3796 advoffset += cplen;
3797 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003799 /*
3800 * Display Wide Board BIOS Information.
3801 */
3802 if (ASC_WIDE_BOARD(boardp)) {
3803 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003804 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003805 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003806 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003807 cplen);
3808 totcnt += cnt;
3809 leftlen -= cnt;
3810 if (leftlen == 0) {
3811 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3812 return totcnt;
3813 }
3814 advoffset += cplen;
3815 curbuf += cnt;
3816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003818 /*
3819 * Display driver information for each device attached to the board.
3820 */
3821 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003822 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003823 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3824 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3825 totcnt += cnt;
3826 leftlen -= cnt;
3827 if (leftlen == 0) {
3828 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3829 return totcnt;
3830 }
3831 advoffset += cplen;
3832 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003834 /*
3835 * Display EEPROM configuration for the board.
3836 */
3837 cp = boardp->prtbuf;
3838 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003839 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003840 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003841 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003842 }
3843 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3844 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3845 totcnt += cnt;
3846 leftlen -= cnt;
3847 if (leftlen == 0) {
3848 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3849 return totcnt;
3850 }
3851 advoffset += cplen;
3852 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003854 /*
3855 * Display driver configuration and information for the board.
3856 */
3857 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003858 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003859 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3860 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3861 totcnt += cnt;
3862 leftlen -= cnt;
3863 if (leftlen == 0) {
3864 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3865 return totcnt;
3866 }
3867 advoffset += cplen;
3868 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869
3870#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003871 /*
3872 * Display driver statistics for the board.
3873 */
3874 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003875 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003876 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
3877 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3878 totcnt += cnt;
3879 leftlen -= cnt;
3880 if (leftlen == 0) {
3881 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3882 return totcnt;
3883 }
3884 advoffset += cplen;
3885 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003887 /*
3888 * Display driver statistics for each target.
3889 */
3890 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
3891 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003892 cplen = asc_prt_target_stats(shost, tgt_id, cp,
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003893 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003894 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003895 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
3896 cplen);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003897 totcnt += cnt;
3898 leftlen -= cnt;
3899 if (leftlen == 0) {
3900 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3901 return totcnt;
3902 }
3903 advoffset += cplen;
3904 curbuf += cnt;
3905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906#endif /* ADVANSYS_STATS */
3907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003908 /*
3909 * Display Asc Library dynamic configuration information
3910 * for the board.
3911 */
3912 cp = boardp->prtbuf;
3913 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003914 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003915 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003916 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003917 }
3918 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3919 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3920 totcnt += cnt;
3921 leftlen -= cnt;
3922 if (leftlen == 0) {
3923 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3924 return totcnt;
3925 }
3926 advoffset += cplen;
3927 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003929 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003931 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932}
3933#endif /* CONFIG_PROC_FS */
3934
3935/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 * advansys_info()
3937 *
3938 * Return suitable for printing on the console with the argument
3939 * adapter's configuration information.
3940 *
3941 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
3942 * otherwise the static 'info' array will be overrun.
3943 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003944static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003946 static char info[ASC_INFO_SIZE];
3947 asc_board_t *boardp;
3948 ASC_DVC_VAR *asc_dvc_varp;
3949 ADV_DVC_VAR *adv_dvc_varp;
3950 char *busname;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003951 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003953 boardp = ASC_BOARDP(shost);
3954 if (ASC_NARROW_BOARD(boardp)) {
3955 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
3956 ASC_DBG(1, "advansys_info: begin\n");
3957 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
3958 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
3959 ASC_IS_ISAPNP) {
3960 busname = "ISA PnP";
3961 } else {
3962 busname = "ISA";
3963 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003964 sprintf(info,
3965 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
3966 ASC_VERSION, busname,
3967 (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003968 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3969 shost->irq, shost->dma_channel);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003970 } else {
3971 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
3972 busname = "VL";
3973 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
3974 busname = "EISA";
3975 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
3976 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
3977 == ASC_IS_PCI_ULTRA) {
3978 busname = "PCI Ultra";
3979 } else {
3980 busname = "PCI";
3981 }
3982 } else {
3983 busname = "?";
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003984 ASC_PRINT2("advansys_info: board %d: unknown "
3985 "bus type %d\n", boardp->id,
3986 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003987 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003988 sprintf(info,
3989 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003990 ASC_VERSION, busname, (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003991 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3992 shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003993 }
3994 } else {
3995 /*
3996 * Wide Adapter Information
3997 *
3998 * Memory-mapped I/O is used instead of I/O space to access
3999 * the adapter, but display the I/O Port range. The Memory
4000 * I/O address is displayed through the driver /proc file.
4001 */
4002 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4003 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004004 widename = "Ultra-Wide";
4005 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004006 widename = "Ultra2-Wide";
4007 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004008 widename = "Ultra3-Wide";
4009 }
4010 sprintf(info,
4011 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
4012 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04004013 (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004014 }
4015 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
4016 ASC_DBG(1, "advansys_info: end\n");
4017 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018}
4019
4020/*
4021 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
4022 *
4023 * This function always returns 0. Command return status is saved
4024 * in the 'scp' result field.
4025 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004026static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004027advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004029 struct Scsi_Host *shost;
4030 asc_board_t *boardp;
4031 ulong flags;
4032 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004034 shost = scp->device->host;
4035 boardp = ASC_BOARDP(shost);
4036 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004038 /* host_lock taken by mid-level prior to call but need to protect */
4039 /* against own ISR */
4040 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004042 /*
4043 * Block new commands while handling a reset or abort request.
4044 */
4045 if (boardp->flags & ASC_HOST_IN_RESET) {
4046 ASC_DBG1(1,
4047 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4048 (ulong)scp);
4049 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004051 /*
4052 * Add blocked requests to the board's 'done' queue. The queued
4053 * requests will be completed at the end of the abort or reset
4054 * handling.
4055 */
4056 asc_enqueue(&boardp->done, scp, ASC_BACK);
4057 spin_unlock_irqrestore(&boardp->lock, flags);
4058 return 0;
4059 }
4060
4061 /*
4062 * Attempt to execute any waiting commands for the board.
4063 */
4064 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4065 ASC_DBG(1,
4066 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4067 asc_execute_queue(&boardp->waiting);
4068 }
4069
4070 /*
4071 * Save the function pointer to Linux mid-level 'done' function
4072 * and attempt to execute the command.
4073 *
4074 * If ASC_NOERROR is returned the request has been added to the
4075 * board's 'active' queue and will be completed by the interrupt
4076 * handler.
4077 *
4078 * If ASC_BUSY is returned add the request to the board's per
4079 * target waiting list. This is the first time the request has
4080 * been tried. Add it to the back of the waiting list. It will be
4081 * retried later.
4082 *
4083 * If an error occurred, the request will have been placed on the
4084 * board's 'done' queue and must be completed before returning.
4085 */
4086 scp->scsi_done = done;
4087 switch (asc_execute_scsi_cmnd(scp)) {
4088 case ASC_NOERROR:
4089 break;
4090 case ASC_BUSY:
4091 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4092 break;
4093 case ASC_ERROR:
4094 default:
4095 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4096 /* Interrupts could be enabled here. */
4097 asc_scsi_done_list(done_scp);
4098 break;
4099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004102 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103}
4104
4105/*
4106 * advansys_reset()
4107 *
4108 * Reset the bus associated with the command 'scp'.
4109 *
4110 * This function runs its own thread. Interrupts must be blocked but
4111 * sleeping is allowed and no locking other than for host structures is
4112 * required. Returns SUCCESS or FAILED.
4113 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004114static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004116 struct Scsi_Host *shost;
4117 asc_board_t *boardp;
4118 ASC_DVC_VAR *asc_dvc_varp;
4119 ADV_DVC_VAR *adv_dvc_varp;
4120 ulong flags;
4121 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4122 struct scsi_cmnd *tscp, *new_last_scp;
4123 int status;
4124 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004126 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127
4128#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004129 if (scp->device->host != NULL) {
4130 ASC_STATS(scp->device->host, reset);
4131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132#endif /* ADVANSYS_STATS */
4133
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004134 if ((shost = scp->device->host) == NULL) {
4135 scp->result = HOST_BYTE(DID_ERROR);
4136 return FAILED;
4137 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004139 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004141 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4142 boardp->id);
4143 /*
4144 * Check for re-entrancy.
4145 */
4146 spin_lock_irqsave(&boardp->lock, flags);
4147 if (boardp->flags & ASC_HOST_IN_RESET) {
4148 spin_unlock_irqrestore(&boardp->lock, flags);
4149 return FAILED;
4150 }
4151 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004154 if (ASC_NARROW_BOARD(boardp)) {
4155 /*
4156 * Narrow Board
4157 */
4158 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004160 /*
4161 * Reset the chip and SCSI bus.
4162 */
4163 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4164 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004166 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4167 if (asc_dvc_varp->err_code) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004168 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4169 "error: 0x%x\n", boardp->id,
4170 asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004171 ret = FAILED;
4172 } else if (status) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004173 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4174 "warning: 0x%x\n", boardp->id, status);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004175 } else {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004176 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4177 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004180 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4181 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004183 } else {
4184 /*
4185 * Wide Board
4186 *
4187 * If the suggest reset bus flags are set, then reset the bus.
4188 * Otherwise only reset the device.
4189 */
4190 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004192 /*
4193 * Reset the target's SCSI bus.
4194 */
4195 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4196 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4197 case ASC_TRUE:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004198 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4199 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004200 break;
4201 case ASC_FALSE:
4202 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004203 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4204 "error.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004205 ret = FAILED;
4206 break;
4207 }
4208 spin_lock_irqsave(&boardp->lock, flags);
4209 (void)AdvISR(adv_dvc_varp);
4210 }
4211 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004213 /*
4214 * Dequeue all board 'done' requests. A pointer to the last request
4215 * is returned in 'last_scp'.
4216 */
4217 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004219 /*
4220 * Dequeue all board 'active' requests for all devices and set
4221 * the request status to DID_RESET. A pointer to the last request
4222 * is returned in 'last_scp'.
4223 */
4224 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004225 done_scp = asc_dequeue_list(&boardp->active, &last_scp,
4226 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004227 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4228 tscp->result = HOST_BYTE(DID_RESET);
4229 }
4230 } else {
4231 /* Append to 'done_scp' at the end with 'last_scp'. */
4232 ASC_ASSERT(last_scp != NULL);
4233 last_scp->host_scribble =
4234 (unsigned char *)asc_dequeue_list(&boardp->active,
4235 &new_last_scp,
4236 ASC_TID_ALL);
4237 if (new_last_scp != NULL) {
4238 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4239 for (tscp = REQPNEXT(last_scp); tscp;
4240 tscp = REQPNEXT(tscp)) {
4241 tscp->result = HOST_BYTE(DID_RESET);
4242 }
4243 last_scp = new_last_scp;
4244 }
4245 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004247 /*
4248 * Dequeue all 'waiting' requests and set the request status
4249 * to DID_RESET.
4250 */
4251 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004252 done_scp = asc_dequeue_list(&boardp->waiting, &last_scp,
4253 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004254 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4255 tscp->result = HOST_BYTE(DID_RESET);
4256 }
4257 } else {
4258 /* Append to 'done_scp' at the end with 'last_scp'. */
4259 ASC_ASSERT(last_scp != NULL);
4260 last_scp->host_scribble =
4261 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4262 &new_last_scp,
4263 ASC_TID_ALL);
4264 if (new_last_scp != NULL) {
4265 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4266 for (tscp = REQPNEXT(last_scp); tscp;
4267 tscp = REQPNEXT(tscp)) {
4268 tscp->result = HOST_BYTE(DID_RESET);
4269 }
4270 last_scp = new_last_scp;
4271 }
4272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004274 /* Save the time of the most recently completed reset. */
4275 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004277 /* Clear reset flag. */
4278 boardp->flags &= ~ASC_HOST_IN_RESET;
4279 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004281 /*
4282 * Complete all the 'done_scp' requests.
4283 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004284 if (done_scp)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004285 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004287 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004289 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290}
4291
4292/*
4293 * advansys_biosparam()
4294 *
4295 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4296 * support is enabled for a drive.
4297 *
4298 * ip (information pointer) is an int array with the following definition:
4299 * ip[0]: heads
4300 * ip[1]: sectors
4301 * ip[2]: cylinders
4302 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004303static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004305 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004307 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004309 ASC_DBG(1, "advansys_biosparam: begin\n");
4310 ASC_STATS(sdev->host, biosparam);
4311 boardp = ASC_BOARDP(sdev->host);
4312 if (ASC_NARROW_BOARD(boardp)) {
4313 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4314 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4315 ip[0] = 255;
4316 ip[1] = 63;
4317 } else {
4318 ip[0] = 64;
4319 ip[1] = 32;
4320 }
4321 } else {
4322 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4323 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4324 ip[0] = 255;
4325 ip[1] = 63;
4326 } else {
4327 ip[0] = 64;
4328 ip[1] = 32;
4329 }
4330 }
4331 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4332 ASC_DBG(1, "advansys_biosparam: end\n");
4333 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334}
4335
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004336static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004337 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004339 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004341 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004342 .info = advansys_info,
4343 .queuecommand = advansys_queuecommand,
4344 .eh_bus_reset_handler = advansys_reset,
4345 .bios_param = advansys_biosparam,
4346 .slave_configure = advansys_slave_configure,
4347 /*
4348 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004349 * must be set. The flag will be cleared in advansys_board_found
4350 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004351 */
4352 .unchecked_isa_dma = 1,
4353 /*
4354 * All adapters controlled by this driver are capable of large
4355 * scatter-gather lists. According to the mid-level SCSI documentation
4356 * this obviates any performance gain provided by setting
4357 * 'use_clustering'. But empirically while CPU utilization is increased
4358 * by enabling clustering, I/O throughput increases as well.
4359 */
4360 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363/*
4364 * --- Miscellaneous Driver Functions
4365 */
4366
4367/*
4368 * First-level interrupt handler.
4369 *
4370 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4371 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4372 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4373 * to the AdvanSys driver which is for a device sharing an interrupt with
4374 * an AdvanSys adapter.
4375 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004376static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004378 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004379 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4380 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004381 struct Scsi_Host *shost = dev_id;
4382 asc_board_t *boardp = ASC_BOARDP(shost);
4383 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004385 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
4386 spin_lock_irqsave(&boardp->lock, flags);
4387 if (ASC_NARROW_BOARD(boardp)) {
4388 /*
4389 * Narrow Board
4390 */
4391 if (AscIsIntPending(shost->io_port)) {
4392 result = IRQ_HANDLED;
4393 ASC_STATS(shost, interrupt);
4394 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
4395 AscISR(&boardp->dvc_var.asc_dvc_var);
4396 }
4397 } else {
4398 /*
4399 * Wide Board
4400 */
4401 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4402 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4403 result = IRQ_HANDLED;
4404 ASC_STATS(shost, interrupt);
4405 }
4406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004408 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004409 * Start waiting requests and create a list of completed requests.
4410 *
4411 * If a reset request is being performed for the board, the reset
4412 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004413 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004414 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4415 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
4416 "last_scp 0x%p\n", done_scp, last_scp);
4417
4418 /* Start any waiting commands for the board. */
4419 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4420 ASC_DBG(1, "advansys_interrupt: before "
4421 "asc_execute_queue()\n");
4422 asc_execute_queue(&boardp->waiting);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004425 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004426 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004427 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004428 * 'done_scp' will always be NULL on the first iteration of
4429 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004430 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004431 if (done_scp == NULL) {
4432 done_scp = asc_dequeue_list(&boardp->done,
4433 &last_scp, ASC_TID_ALL);
4434 } else {
4435 ASC_ASSERT(last_scp != NULL);
4436 last_scp->host_scribble =
4437 (unsigned char *)asc_dequeue_list(&boardp->
4438 done,
4439 &new_last_scp,
4440 ASC_TID_ALL);
4441 if (new_last_scp != NULL) {
4442 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4443 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004444 }
4445 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004446 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004447 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004449 /*
4450 * If interrupts were enabled on entry, then they
4451 * are now enabled here.
4452 *
4453 * Complete all requests on the done list.
4454 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004456 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004458 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004459 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460}
4461
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004462static void
4463advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
4464{
4465 ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
4466 ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
4467
4468 if (sdev->lun == 0) {
4469 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
4470 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
4471 asc_dvc->init_sdtr |= tid_bit;
4472 } else {
4473 asc_dvc->init_sdtr &= ~tid_bit;
4474 }
4475
4476 if (orig_init_sdtr != asc_dvc->init_sdtr)
4477 AscAsyncFix(asc_dvc, sdev);
4478 }
4479
4480 if (sdev->tagged_supported) {
4481 if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
4482 if (sdev->lun == 0) {
4483 asc_dvc->cfg->can_tagged_qng |= tid_bit;
4484 asc_dvc->use_tagged_qng |= tid_bit;
4485 }
4486 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4487 asc_dvc->max_dvc_qng[sdev->id]);
4488 }
4489 } else {
4490 if (sdev->lun == 0) {
4491 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
4492 asc_dvc->use_tagged_qng &= ~tid_bit;
4493 }
4494 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4495 }
4496
4497 if ((sdev->lun == 0) &&
4498 (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
4499 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
4500 asc_dvc->cfg->disc_enable);
4501 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
4502 asc_dvc->use_tagged_qng);
4503 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
4504 asc_dvc->cfg->can_tagged_qng);
4505
4506 asc_dvc->max_dvc_qng[sdev->id] =
4507 asc_dvc->cfg->max_tag_qng[sdev->id];
4508 AscWriteLramByte(asc_dvc->iop_base,
4509 (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
4510 asc_dvc->max_dvc_qng[sdev->id]);
4511 }
4512}
4513
4514/*
4515 * Wide Transfers
4516 *
4517 * If the EEPROM enabled WDTR for the device and the device supports wide
4518 * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
4519 * write the new value to the microcode.
4520 */
4521static void
4522advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
4523{
4524 unsigned short cfg_word;
4525 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4526 if ((cfg_word & tidmask) != 0)
4527 return;
4528
4529 cfg_word |= tidmask;
4530 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4531
4532 /*
4533 * Clear the microcode SDTR and WDTR negotiation done indicators for
4534 * the target to cause it to negotiate with the new setting set above.
4535 * WDTR when accepted causes the target to enter asynchronous mode, so
4536 * SDTR must be negotiated.
4537 */
4538 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4539 cfg_word &= ~tidmask;
4540 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4541 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4542 cfg_word &= ~tidmask;
4543 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4544}
4545
4546/*
4547 * Synchronous Transfers
4548 *
4549 * If the EEPROM enabled SDTR for the device and the device
4550 * supports synchronous transfers, then turn on the device's
4551 * 'sdtr_able' bit. Write the new value to the microcode.
4552 */
4553static void
4554advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
4555{
4556 unsigned short cfg_word;
4557 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4558 if ((cfg_word & tidmask) != 0)
4559 return;
4560
4561 cfg_word |= tidmask;
4562 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4563
4564 /*
4565 * Clear the microcode "SDTR negotiation" done indicator for the
4566 * target to cause it to negotiate with the new setting set above.
4567 */
4568 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4569 cfg_word &= ~tidmask;
4570 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4571}
4572
4573/*
4574 * PPR (Parallel Protocol Request) Capable
4575 *
4576 * If the device supports DT mode, then it must be PPR capable.
4577 * The PPR message will be used in place of the SDTR and WDTR
4578 * messages to negotiate synchronous speed and offset, transfer
4579 * width, and protocol options.
4580 */
4581static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
4582 AdvPortAddr iop_base, unsigned short tidmask)
4583{
4584 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4585 adv_dvc->ppr_able |= tidmask;
4586 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4587}
4588
4589static void
4590advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
4591{
4592 AdvPortAddr iop_base = adv_dvc->iop_base;
4593 unsigned short tidmask = 1 << sdev->id;
4594
4595 if (sdev->lun == 0) {
4596 /*
4597 * Handle WDTR, SDTR, and Tag Queuing. If the feature
4598 * is enabled in the EEPROM and the device supports the
4599 * feature, then enable it in the microcode.
4600 */
4601
4602 if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
4603 advansys_wide_enable_wdtr(iop_base, tidmask);
4604 if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
4605 advansys_wide_enable_sdtr(iop_base, tidmask);
4606 if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
4607 advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
4608
4609 /*
4610 * Tag Queuing is disabled for the BIOS which runs in polled
4611 * mode and would see no benefit from Tag Queuing. Also by
4612 * disabling Tag Queuing in the BIOS devices with Tag Queuing
4613 * bugs will at least work with the BIOS.
4614 */
4615 if ((adv_dvc->tagqng_able & tidmask) &&
4616 sdev->tagged_supported) {
4617 unsigned short cfg_word;
4618 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
4619 cfg_word |= tidmask;
4620 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
4621 cfg_word);
4622 AdvWriteByteLram(iop_base,
4623 ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
4624 adv_dvc->max_dvc_qng);
4625 }
4626 }
4627
4628 if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
4629 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4630 adv_dvc->max_dvc_qng);
4631 } else {
4632 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4633 }
4634}
4635
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636/*
4637 * Set the number of commands to queue per device for the
4638 * specified host adapter.
4639 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004640static int advansys_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004642 asc_board_t *boardp = ASC_BOARDP(sdev->host);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004643 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004644
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004645 /*
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004646 * Save a pointer to the sdev and set its initial/maximum
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004647 * queue depth. Only save the pointer for a lun0 dev though.
4648 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004649 if (sdev->lun == 0)
4650 boardp->device[sdev->id] = sdev;
4651
4652 if (ASC_NARROW_BOARD(boardp))
4653 advansys_narrow_slave_configure(sdev,
4654 &boardp->dvc_var.asc_dvc_var);
4655 else
4656 advansys_wide_slave_configure(sdev,
4657 &boardp->dvc_var.adv_dvc_var);
4658
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004659 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660}
4661
4662/*
4663 * Complete all requests on the singly linked list pointed
4664 * to by 'scp'.
4665 *
4666 * Interrupts can be enabled on entry.
4667 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004668static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004670 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004672 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4673 while (scp != NULL) {
4674 asc_board_t *boardp;
4675 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004677 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4678 tscp = REQPNEXT(scp);
4679 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004681 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004683 if (ASC_NARROW_BOARD(boardp))
4684 dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
4685 else
4686 dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004688 if (scp->use_sg)
4689 dma_unmap_sg(dev,
4690 (struct scatterlist *)scp->request_buffer,
4691 scp->use_sg, scp->sc_data_direction);
4692 else if (scp->request_bufflen)
4693 dma_unmap_single(dev, scp->SCp.dma_handle,
4694 scp->request_bufflen,
4695 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004697 ASC_STATS(scp->device->host, done);
4698 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004700 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004702 scp = tscp;
4703 }
4704 ASC_DBG(2, "asc_scsi_done_list: done\n");
4705 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706}
4707
4708/*
4709 * Execute a single 'Scsi_Cmnd'.
4710 *
4711 * The function 'done' is called when the request has been completed.
4712 *
4713 * Scsi_Cmnd:
4714 *
4715 * host - board controlling device
4716 * device - device to send command
4717 * target - target of device
4718 * lun - lun of device
4719 * cmd_len - length of SCSI CDB
4720 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4721 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4722 *
4723 * if (use_sg == 0) {
4724 * request_buffer - buffer address for request
4725 * request_bufflen - length of request buffer
4726 * } else {
4727 * request_buffer - pointer to scatterlist structure
4728 * }
4729 *
4730 * sense_buffer - sense command buffer
4731 *
4732 * result (4 bytes of an int):
4733 * Byte Meaning
4734 * 0 SCSI Status Byte Code
4735 * 1 SCSI One Byte Message Code
4736 * 2 Host Error Code
4737 * 3 Mid-Level Error Code
4738 *
4739 * host driver fields:
4740 * SCp - Scsi_Pointer used for command processing status
4741 * scsi_done - used to save caller's done function
4742 * host_scribble - used for pointer to another struct scsi_cmnd
4743 *
4744 * If this function returns ASC_NOERROR the request has been enqueued
4745 * on the board's 'active' queue and will be completed from the
4746 * interrupt handler.
4747 *
4748 * If this function returns ASC_NOERROR the request has been enqueued
4749 * on the board's 'done' queue and must be completed by the caller.
4750 *
4751 * If ASC_BUSY is returned the request will be enqueued by the
4752 * caller on the target's waiting queue and re-tried later.
4753 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004754static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004756 asc_board_t *boardp;
4757 ASC_DVC_VAR *asc_dvc_varp;
4758 ADV_DVC_VAR *adv_dvc_varp;
4759 ADV_SCSI_REQ_Q *adv_scsiqp;
4760 struct scsi_device *device;
4761 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004763 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4764 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004766 boardp = ASC_BOARDP(scp->device->host);
4767 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004769 if (ASC_NARROW_BOARD(boardp)) {
4770 /*
4771 * Build and execute Narrow Board request.
4772 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004774 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004776 /*
4777 * Build Asc Library request structure using the
4778 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4779 *
4780 * If an error is returned, then the request has been
4781 * queued on the board done queue. It will be completed
4782 * by the caller.
4783 *
4784 * asc_build_req() can not return ASC_BUSY.
4785 */
4786 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4787 ASC_STATS(scp->device->host, build_error);
4788 return ASC_ERROR;
4789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004791 /*
4792 * Execute the command. If there is no error, add the command
4793 * to the active queue.
4794 */
4795 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4796 case ASC_NOERROR:
4797 ASC_STATS(scp->device->host, exe_noerror);
4798 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004799 * Increment monotonically increasing per device
4800 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004801 */
4802 boardp->reqcnt[scp->device->id]++;
4803 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004804 ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), "
4805 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004806 break;
4807 case ASC_BUSY:
4808 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004809 * Caller will enqueue request on the target's waiting
4810 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004811 */
4812 ASC_STATS(scp->device->host, exe_busy);
4813 break;
4814 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004815 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4816 "AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4817 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004818 ASC_STATS(scp->device->host, exe_error);
4819 scp->result = HOST_BYTE(DID_ERROR);
4820 asc_enqueue(&boardp->done, scp, ASC_BACK);
4821 break;
4822 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004823 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4824 "AscExeScsiQueue() unknown, err_code 0x%x\n",
4825 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004826 ASC_STATS(scp->device->host, exe_unknown);
4827 scp->result = HOST_BYTE(DID_ERROR);
4828 asc_enqueue(&boardp->done, scp, ASC_BACK);
4829 break;
4830 }
4831 } else {
4832 /*
4833 * Build and execute Wide Board request.
4834 */
4835 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004837 /*
4838 * Build and get a pointer to an Adv Library request structure.
4839 *
4840 * If the request is successfully built then send it below,
4841 * otherwise return with an error.
4842 */
4843 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4844 case ASC_NOERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004845 ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req "
4846 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004847 break;
4848 case ASC_BUSY:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004849 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4850 "ASC_BUSY\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004851 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004852 * If busy is returned the request has not been
4853 * enqueued. It will be enqueued by the caller on the
4854 * target's waiting queue and retried later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004855 *
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004856 * The asc_stats fields 'adv_build_noreq' and
4857 * 'adv_build_nosg' count wide board busy conditions.
4858 * They are updated in adv_build_req and
4859 * adv_get_sglist, respectively.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004860 */
4861 return ASC_BUSY;
4862 case ASC_ERROR:
4863 /*
4864 * If an error is returned, then the request has been
4865 * queued on the board done queue. It will be completed
4866 * by the caller.
4867 */
4868 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004869 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4870 "ASC_ERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004871 ASC_STATS(scp->device->host, build_error);
4872 return ASC_ERROR;
4873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004875 /*
4876 * Execute the command. If there is no error, add the command
4877 * to the active queue.
4878 */
4879 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
4880 case ASC_NOERROR:
4881 ASC_STATS(scp->device->host, exe_noerror);
4882 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004883 * Increment monotonically increasing per device
4884 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004885 */
4886 boardp->reqcnt[scp->device->id]++;
4887 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004888 ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), "
4889 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004890 break;
4891 case ASC_BUSY:
4892 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004893 * Caller will enqueue request on the target's waiting
4894 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004895 */
4896 ASC_STATS(scp->device->host, exe_busy);
4897 break;
4898 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004899 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4900 "AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4901 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004902 ASC_STATS(scp->device->host, exe_error);
4903 scp->result = HOST_BYTE(DID_ERROR);
4904 asc_enqueue(&boardp->done, scp, ASC_BACK);
4905 break;
4906 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004907 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4908 "AdvExeScsiQueue() unknown, err_code 0x%x\n",
4909 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004910 ASC_STATS(scp->device->host, exe_unknown);
4911 scp->result = HOST_BYTE(DID_ERROR);
4912 asc_enqueue(&boardp->done, scp, ASC_BACK);
4913 break;
4914 }
4915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004917 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
4918 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919}
4920
4921/*
4922 * Build a request structure for the Asc Library (Narrow Board).
4923 *
4924 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
4925 * used to build the request.
4926 *
4927 * If an error occurs, then queue the request on the board done
4928 * queue and return ASC_ERROR.
4929 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004930static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004932 struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004934 /*
4935 * Mutually exclusive access is required to 'asc_scsi_q' and
4936 * 'asc_sg_head' until after the request is started.
4937 */
4938 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004940 /*
4941 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
4942 */
4943 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004945 /*
4946 * Build the ASC_SCSI_Q request.
4947 *
4948 * For narrow boards a CDB length maximum of 12 bytes
4949 * is supported.
4950 */
4951 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004952 ASC_PRINT3("asc_build_req: board %d: cmd_len %d > "
4953 "ASC_MAX_CDB_LEN %d\n", boardp->id, scp->cmd_len,
4954 ASC_MAX_CDB_LEN);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004955 scp->result = HOST_BYTE(DID_ERROR);
4956 asc_enqueue(&boardp->done, scp, ASC_BACK);
4957 return ASC_ERROR;
4958 }
4959 asc_scsi_q.cdbptr = &scp->cmnd[0];
4960 asc_scsi_q.q2.cdb_len = scp->cmd_len;
4961 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
4962 asc_scsi_q.q1.target_lun = scp->device->lun;
4963 asc_scsi_q.q2.target_ix =
4964 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
4965 asc_scsi_q.q1.sense_addr =
4966 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4967 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004969 /*
4970 * If there are any outstanding requests for the current target,
4971 * then every 255th request send an ORDERED request. This heuristic
4972 * tries to retain the benefit of request sorting while preventing
4973 * request starvation. 255 is the max number of tags or pending commands
4974 * a device may have outstanding.
4975 *
4976 * The request count is incremented below for every successfully
4977 * started request.
4978 *
4979 */
4980 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
4981 (boardp->reqcnt[scp->device->id] % 255) == 0) {
4982 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
4983 } else {
4984 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
4985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004987 /*
4988 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
4989 * buffer command.
4990 */
4991 if (scp->use_sg == 0) {
4992 /*
4993 * CDB request of single contiguous buffer.
4994 */
4995 ASC_STATS(scp->device->host, cont_cnt);
4996 scp->SCp.dma_handle = scp->request_bufflen ?
4997 dma_map_single(dev, scp->request_buffer,
4998 scp->request_bufflen,
4999 scp->sc_data_direction) : 0;
5000 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
5001 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
5002 ASC_STATS_ADD(scp->device->host, cont_xfer,
5003 ASC_CEILING(scp->request_bufflen, 512));
5004 asc_scsi_q.q1.sg_queue_cnt = 0;
5005 asc_scsi_q.sg_head = NULL;
5006 } else {
5007 /*
5008 * CDB scatter-gather request list.
5009 */
5010 int sgcnt;
5011 int use_sg;
5012 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005014 slp = (struct scatterlist *)scp->request_buffer;
5015 use_sg =
5016 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005018 if (use_sg > scp->device->host->sg_tablesize) {
5019 ASC_PRINT3
5020 ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
5021 boardp->id, use_sg,
5022 scp->device->host->sg_tablesize);
5023 dma_unmap_sg(dev, slp, scp->use_sg,
5024 scp->sc_data_direction);
5025 scp->result = HOST_BYTE(DID_ERROR);
5026 asc_enqueue(&boardp->done, scp, ASC_BACK);
5027 return ASC_ERROR;
5028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005030 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005032 /*
5033 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
5034 * structure to point to it.
5035 */
5036 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005038 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5039 asc_scsi_q.sg_head = &asc_sg_head;
5040 asc_scsi_q.q1.data_cnt = 0;
5041 asc_scsi_q.q1.data_addr = 0;
5042 /* This is a byte value, otherwise it would need to be swapped. */
5043 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5044 ASC_STATS_ADD(scp->device->host, sg_elem,
5045 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005047 /*
5048 * Convert scatter-gather list into ASC_SG_HEAD list.
5049 */
5050 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5051 asc_sg_head.sg_list[sgcnt].addr =
5052 cpu_to_le32(sg_dma_address(slp));
5053 asc_sg_head.sg_list[sgcnt].bytes =
5054 cpu_to_le32(sg_dma_len(slp));
5055 ASC_STATS_ADD(scp->device->host, sg_xfer,
5056 ASC_CEILING(sg_dma_len(slp), 512));
5057 }
5058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005060 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5061 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005063 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064}
5065
5066/*
5067 * Build a request structure for the Adv Library (Wide Board).
5068 *
5069 * If an adv_req_t can not be allocated to issue the request,
5070 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5071 *
5072 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5073 * microcode for DMA addresses or math operations are byte swapped
5074 * to little-endian order.
5075 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005076static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005078 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005080 adv_req_t *reqp;
5081 ADV_SCSI_REQ_Q *scsiqp;
5082 int i;
5083 int ret;
5084 struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005086 /*
5087 * Allocate an adv_req_t structure from the board to execute
5088 * the command.
5089 */
5090 if (boardp->adv_reqp == NULL) {
5091 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5092 ASC_STATS(scp->device->host, adv_build_noreq);
5093 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005095 reqp = boardp->adv_reqp;
5096 boardp->adv_reqp = reqp->next_reqp;
5097 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005100 /*
5101 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5102 */
5103 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005105 /*
5106 * Initialize the structure.
5107 */
5108 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005110 /*
5111 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5112 */
5113 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005115 /*
5116 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5117 */
5118 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005120 /*
5121 * Build the ADV_SCSI_REQ_Q request.
5122 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005124 /*
5125 * Set CDB length and copy it to the request structure.
5126 * For wide boards a CDB length maximum of 16 bytes
5127 * is supported.
5128 */
5129 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5130 ASC_PRINT3
5131 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5132 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5133 scp->result = HOST_BYTE(DID_ERROR);
5134 asc_enqueue(&boardp->done, scp, ASC_BACK);
5135 return ASC_ERROR;
5136 }
5137 scsiqp->cdb_len = scp->cmd_len;
5138 /* Copy first 12 CDB bytes to cdb[]. */
5139 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5140 scsiqp->cdb[i] = scp->cmnd[i];
5141 }
5142 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5143 for (; i < scp->cmd_len; i++) {
5144 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005147 scsiqp->target_id = scp->device->id;
5148 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005150 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5151 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005153 /*
5154 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5155 * buffer command.
5156 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005158 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5159 scsiqp->vdata_addr = scp->request_buffer;
5160 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5161
5162 if (scp->use_sg == 0) {
5163 /*
5164 * CDB request of single contiguous buffer.
5165 */
5166 reqp->sgblkp = NULL;
5167 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5168 if (scp->request_bufflen) {
5169 scsiqp->vdata_addr = scp->request_buffer;
5170 scp->SCp.dma_handle =
5171 dma_map_single(dev, scp->request_buffer,
5172 scp->request_bufflen,
5173 scp->sc_data_direction);
5174 } else {
5175 scsiqp->vdata_addr = NULL;
5176 scp->SCp.dma_handle = 0;
5177 }
5178 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5179 scsiqp->sg_list_ptr = NULL;
5180 scsiqp->sg_real_addr = 0;
5181 ASC_STATS(scp->device->host, cont_cnt);
5182 ASC_STATS_ADD(scp->device->host, cont_xfer,
5183 ASC_CEILING(scp->request_bufflen, 512));
5184 } else {
5185 /*
5186 * CDB scatter-gather request list.
5187 */
5188 struct scatterlist *slp;
5189 int use_sg;
5190
5191 slp = (struct scatterlist *)scp->request_buffer;
5192 use_sg =
5193 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
5194
5195 if (use_sg > ADV_MAX_SG_LIST) {
5196 ASC_PRINT3
5197 ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
5198 boardp->id, use_sg,
5199 scp->device->host->sg_tablesize);
5200 dma_unmap_sg(dev, slp, scp->use_sg,
5201 scp->sc_data_direction);
5202 scp->result = HOST_BYTE(DID_ERROR);
5203 asc_enqueue(&boardp->done, scp, ASC_BACK);
5204
5205 /*
5206 * Free the 'adv_req_t' structure by adding it back to the
5207 * board free list.
5208 */
5209 reqp->next_reqp = boardp->adv_reqp;
5210 boardp->adv_reqp = reqp;
5211
5212 return ASC_ERROR;
5213 }
5214
5215 if ((ret =
5216 adv_get_sglist(boardp, reqp, scp,
5217 use_sg)) != ADV_SUCCESS) {
5218 /*
5219 * Free the adv_req_t structure by adding it back to the
5220 * board free list.
5221 */
5222 reqp->next_reqp = boardp->adv_reqp;
5223 boardp->adv_reqp = reqp;
5224
5225 return ret;
5226 }
5227
5228 ASC_STATS(scp->device->host, sg_cnt);
5229 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5230 }
5231
5232 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5233 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5234
5235 *adv_scsiqpp = scsiqp;
5236
5237 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238}
5239
5240/*
5241 * Build scatter-gather list for Adv Library (Wide Board).
5242 *
5243 * Additional ADV_SG_BLOCK structures will need to be allocated
5244 * if the total number of scatter-gather elements exceeds
5245 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5246 * assumed to be physically contiguous.
5247 *
5248 * Return:
5249 * ADV_SUCCESS(1) - SG List successfully created
5250 * ADV_ERROR(-1) - SG List creation failed
5251 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005252static int
5253adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5254 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005256 adv_sgblk_t *sgblkp;
5257 ADV_SCSI_REQ_Q *scsiqp;
5258 struct scatterlist *slp;
5259 int sg_elem_cnt;
5260 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5261 ADV_PADDR sg_block_paddr;
5262 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005264 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5265 slp = (struct scatterlist *)scp->request_buffer;
5266 sg_elem_cnt = use_sg;
5267 prev_sg_block = NULL;
5268 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005270 do {
5271 /*
5272 * Allocate a 'adv_sgblk_t' structure from the board free
5273 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5274 * (15) scatter-gather elements.
5275 */
5276 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5277 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5278 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005280 /*
5281 * Allocation failed. Free 'adv_sgblk_t' structures already
5282 * allocated for the request.
5283 */
5284 while ((sgblkp = reqp->sgblkp) != NULL) {
5285 /* Remove 'sgblkp' from the request list. */
5286 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005288 /* Add 'sgblkp' to the board free list. */
5289 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5290 boardp->adv_sgblkp = sgblkp;
5291 }
5292 return ASC_BUSY;
5293 } else {
5294 /* Complete 'adv_sgblk_t' board allocation. */
5295 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5296 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005298 /*
5299 * Get 8 byte aligned virtual and physical addresses for
5300 * the allocated ADV_SG_BLOCK structure.
5301 */
5302 sg_block =
5303 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5304 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005306 /*
5307 * Check if this is the first 'adv_sgblk_t' for the request.
5308 */
5309 if (reqp->sgblkp == NULL) {
5310 /* Request's first scatter-gather block. */
5311 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005313 /*
5314 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5315 * address pointers.
5316 */
5317 scsiqp->sg_list_ptr = sg_block;
5318 scsiqp->sg_real_addr =
5319 cpu_to_le32(sg_block_paddr);
5320 } else {
5321 /* Request's second or later scatter-gather block. */
5322 sgblkp->next_sgblkp = reqp->sgblkp;
5323 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005325 /*
5326 * Point the previous ADV_SG_BLOCK structure to
5327 * the newly allocated ADV_SG_BLOCK structure.
5328 */
5329 ASC_ASSERT(prev_sg_block != NULL);
5330 prev_sg_block->sg_ptr =
5331 cpu_to_le32(sg_block_paddr);
5332 }
5333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005335 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5336 sg_block->sg_list[i].sg_addr =
5337 cpu_to_le32(sg_dma_address(slp));
5338 sg_block->sg_list[i].sg_count =
5339 cpu_to_le32(sg_dma_len(slp));
5340 ASC_STATS_ADD(scp->device->host, sg_xfer,
5341 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005343 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5344 sg_block->sg_cnt = i + 1;
5345 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5346 return ADV_SUCCESS;
5347 }
5348 slp++;
5349 }
5350 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5351 prev_sg_block = sg_block;
5352 }
5353 while (1);
5354 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355}
5356
5357/*
5358 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5359 *
5360 * Interrupt callback function for the Narrow SCSI Asc Library.
5361 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005362static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005364 asc_board_t *boardp;
5365 struct scsi_cmnd *scp;
5366 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005368 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5369 (ulong)asc_dvc_varp, (ulong)qdonep);
5370 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005372 /*
5373 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5374 * command that has been completed.
5375 */
5376 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5377 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005379 if (scp == NULL) {
5380 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5381 return;
5382 }
5383 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005385 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005386 ASC_STATS(shost, callback);
5387 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005389 /*
5390 * If the request isn't found on the active queue, it may
5391 * have been removed to handle a reset request.
5392 * Display a message and return.
5393 */
5394 boardp = ASC_BOARDP(shost);
5395 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5396 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5397 ASC_PRINT2
5398 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5399 boardp->id, (ulong)scp);
5400 return;
5401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005403 /*
5404 * 'qdonep' contains the command's ending status.
5405 */
5406 switch (qdonep->d3.done_stat) {
5407 case QD_NO_ERROR:
5408 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5409 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005411 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005412 * Check for an underrun condition.
5413 *
5414 * If there was no error and an underrun condition, then
Matthew Wilcox47d853c2007-07-26 11:41:33 -04005415 * return the number of underrun bytes.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005416 */
5417 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5418 qdonep->remain_bytes <= scp->request_bufflen) {
5419 ASC_DBG1(1,
5420 "asc_isr_callback: underrun condition %u bytes\n",
5421 (unsigned)qdonep->remain_bytes);
5422 scp->resid = qdonep->remain_bytes;
5423 }
5424 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005426 case QD_WITH_ERROR:
5427 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5428 switch (qdonep->d3.host_stat) {
5429 case QHSTA_NO_ERROR:
5430 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5431 ASC_DBG(2,
5432 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5433 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5434 sizeof(scp->sense_buffer));
5435 /*
5436 * Note: The 'status_byte()' macro used by target drivers
5437 * defined in scsi.h shifts the status byte returned by
5438 * host drivers right by 1 bit. This is why target drivers
5439 * also use right shifted status byte definitions. For
5440 * instance target drivers use CHECK_CONDITION, defined to
5441 * 0x1, instead of the SCSI defined check condition value
5442 * of 0x2. Host drivers are supposed to return the status
5443 * byte as it is defined by SCSI.
5444 */
5445 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5446 STATUS_BYTE(qdonep->d3.scsi_stat);
5447 } else {
5448 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5449 }
5450 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005452 default:
5453 /* QHSTA error occurred */
5454 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5455 qdonep->d3.host_stat);
5456 scp->result = HOST_BYTE(DID_BAD_TARGET);
5457 break;
5458 }
5459 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005461 case QD_ABORTED_BY_HOST:
5462 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5463 scp->result =
5464 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5465 scsi_msg) |
5466 STATUS_BYTE(qdonep->d3.scsi_stat);
5467 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005469 default:
5470 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5471 qdonep->d3.done_stat);
5472 scp->result =
5473 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5474 scsi_msg) |
5475 STATUS_BYTE(qdonep->d3.scsi_stat);
5476 break;
5477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005479 /*
5480 * If the 'init_tidmask' bit isn't already set for the target and the
5481 * current request finished normally, then set the bit for the target
5482 * to indicate that a device is present.
5483 */
5484 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5485 qdonep->d3.done_stat == QD_NO_ERROR &&
5486 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5487 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005490 /*
5491 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5492 * function, add the command to the end of the board's done queue.
5493 * The done function for the command will be called from
5494 * advansys_interrupt().
5495 */
5496 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005498 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499}
5500
5501/*
5502 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5503 *
5504 * Callback function for the Wide SCSI Adv Library.
5505 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005506static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005508 asc_board_t *boardp;
5509 adv_req_t *reqp;
5510 adv_sgblk_t *sgblkp;
5511 struct scsi_cmnd *scp;
5512 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005513 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005515 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5516 (ulong)adv_dvc_varp, (ulong)scsiqp);
5517 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005519 /*
5520 * Get the adv_req_t structure for the command that has been
5521 * completed. The adv_req_t structure actually contains the
5522 * completed ADV_SCSI_REQ_Q structure.
5523 */
5524 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5525 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5526 if (reqp == NULL) {
5527 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5528 return;
5529 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005531 /*
5532 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5533 * command that has been completed.
5534 *
5535 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5536 * if any, are dropped, because a board structure pointer can not be
5537 * determined.
5538 */
5539 scp = reqp->cmndp;
5540 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5541 if (scp == NULL) {
5542 ASC_PRINT
5543 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5544 return;
5545 }
5546 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005548 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005549 ASC_STATS(shost, callback);
5550 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005552 /*
5553 * If the request isn't found on the active queue, it may have been
5554 * removed to handle a reset request. Display a message and return.
5555 *
5556 * Note: Because the structure may still be in use don't attempt
5557 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5558 */
5559 boardp = ASC_BOARDP(shost);
5560 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5561 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5562 ASC_PRINT2
5563 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5564 boardp->id, (ulong)scp);
5565 return;
5566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005568 /*
5569 * 'done_status' contains the command's ending status.
5570 */
5571 switch (scsiqp->done_status) {
5572 case QD_NO_ERROR:
5573 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5574 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005576 /*
5577 * Check for an underrun condition.
5578 *
5579 * If there was no error and an underrun condition, then
5580 * then return the number of underrun bytes.
5581 */
5582 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5583 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5584 resid_cnt <= scp->request_bufflen) {
5585 ASC_DBG1(1,
5586 "adv_isr_callback: underrun condition %lu bytes\n",
5587 (ulong)resid_cnt);
5588 scp->resid = resid_cnt;
5589 }
5590 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005592 case QD_WITH_ERROR:
5593 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5594 switch (scsiqp->host_status) {
5595 case QHSTA_NO_ERROR:
5596 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5597 ASC_DBG(2,
5598 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5599 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5600 sizeof(scp->sense_buffer));
5601 /*
5602 * Note: The 'status_byte()' macro used by target drivers
5603 * defined in scsi.h shifts the status byte returned by
5604 * host drivers right by 1 bit. This is why target drivers
5605 * also use right shifted status byte definitions. For
5606 * instance target drivers use CHECK_CONDITION, defined to
5607 * 0x1, instead of the SCSI defined check condition value
5608 * of 0x2. Host drivers are supposed to return the status
5609 * byte as it is defined by SCSI.
5610 */
5611 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5612 STATUS_BYTE(scsiqp->scsi_status);
5613 } else {
5614 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5615 }
5616 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005618 default:
5619 /* Some other QHSTA error occurred. */
5620 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5621 scsiqp->host_status);
5622 scp->result = HOST_BYTE(DID_BAD_TARGET);
5623 break;
5624 }
5625 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005627 case QD_ABORTED_BY_HOST:
5628 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5629 scp->result =
5630 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5631 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005633 default:
5634 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5635 scsiqp->done_status);
5636 scp->result =
5637 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5638 break;
5639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005641 /*
5642 * If the 'init_tidmask' bit isn't already set for the target and the
5643 * current request finished normally, then set the bit for the target
5644 * to indicate that a device is present.
5645 */
5646 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5647 scsiqp->done_status == QD_NO_ERROR &&
5648 scsiqp->host_status == QHSTA_NO_ERROR) {
5649 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005652 /*
5653 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5654 * function, add the command to the end of the board's done queue.
5655 * The done function for the command will be called from
5656 * advansys_interrupt().
5657 */
5658 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005660 /*
5661 * Free all 'adv_sgblk_t' structures allocated for the request.
5662 */
5663 while ((sgblkp = reqp->sgblkp) != NULL) {
5664 /* Remove 'sgblkp' from the request list. */
5665 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005667 /* Add 'sgblkp' to the board free list. */
5668 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5669 boardp->adv_sgblkp = sgblkp;
5670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005672 /*
5673 * Free the adv_req_t structure used with the command by adding
5674 * it back to the board free list.
5675 */
5676 reqp->next_reqp = boardp->adv_reqp;
5677 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005679 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005681 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682}
5683
5684/*
5685 * adv_async_callback() - Adv Library asynchronous event callback function.
5686 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005687static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005689 switch (code) {
5690 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5691 /*
5692 * The firmware detected a SCSI Bus reset.
5693 */
5694 ASC_DBG(0,
5695 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5696 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005698 case ADV_ASYNC_RDMA_FAILURE:
5699 /*
5700 * Handle RDMA failure by resetting the SCSI Bus and
5701 * possibly the chip if it is unresponsive. Log the error
5702 * with a unique code.
5703 */
5704 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5705 AdvResetChipAndSB(adv_dvc_varp);
5706 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005708 case ADV_HOST_SCSI_BUS_RESET:
5709 /*
5710 * Host generated SCSI bus reset occurred.
5711 */
5712 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5713 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005715 default:
5716 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5717 break;
5718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719}
5720
5721/*
5722 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5723 * to indicate a command is queued for the device.
5724 *
5725 * 'flag' may be either ASC_FRONT or ASC_BACK.
5726 *
5727 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5728 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005729static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005731 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005732
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005733 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5734 (ulong)ascq, (ulong)reqp, flag);
5735 ASC_ASSERT(reqp != NULL);
5736 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5737 tid = REQPTID(reqp);
5738 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5739 if (flag == ASC_FRONT) {
5740 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5741 ascq->q_first[tid] = reqp;
5742 /* If the queue was empty, set the last pointer. */
5743 if (ascq->q_last[tid] == NULL) {
5744 ascq->q_last[tid] = reqp;
5745 }
5746 } else { /* ASC_BACK */
5747 if (ascq->q_last[tid] != NULL) {
5748 ascq->q_last[tid]->host_scribble =
5749 (unsigned char *)reqp;
5750 }
5751 ascq->q_last[tid] = reqp;
5752 reqp->host_scribble = NULL;
5753 /* If the queue was empty, set the first pointer. */
5754 if (ascq->q_first[tid] == NULL) {
5755 ascq->q_first[tid] = reqp;
5756 }
5757 }
5758 /* The queue has at least one entry, set its bit. */
5759 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005761 /* Maintain request queue statistics. */
5762 ascq->q_tot_cnt[tid]++;
5763 ascq->q_cur_cnt[tid]++;
5764 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5765 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5766 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5767 tid, ascq->q_max_cnt[tid]);
5768 }
5769 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005771 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5772 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773}
5774
5775/*
5776 * Return first queued 'REQP' on the specified queue for
5777 * the specified target device. Clear the 'tidmask' bit for
5778 * the device if no more commands are left queued for it.
5779 *
5780 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5781 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005782static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005784 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005786 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5787 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5788 if ((reqp = ascq->q_first[tid]) != NULL) {
5789 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5790 ascq->q_first[tid] = REQPNEXT(reqp);
5791 /* If the queue is empty, clear its bit and the last pointer. */
5792 if (ascq->q_first[tid] == NULL) {
5793 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5794 ASC_ASSERT(ascq->q_last[tid] == reqp);
5795 ascq->q_last[tid] = NULL;
5796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005797#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005798 /* Maintain request queue statistics. */
5799 ascq->q_cur_cnt[tid]--;
5800 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
5801 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005803 }
5804 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
5805 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806}
5807
5808/*
5809 * Return a pointer to a singly linked list of all the requests queued
5810 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
5811 *
5812 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
5813 * the last request returned in the singly linked list.
5814 *
5815 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
5816 * then all queued requests are concatenated into one list and
5817 * returned.
5818 *
5819 * Note: If 'lastpp' is used to append a new list to the end of
5820 * an old list, only change the old list last pointer if '*lastpp'
5821 * (or the function return value) is not NULL, i.e. use a temporary
5822 * variable for 'lastpp' and check its value after the function return
5823 * before assigning it to the list last pointer.
5824 *
5825 * Unfortunately collecting queuing time statistics adds overhead to
5826 * the function that isn't inherent to the function's algorithm.
5827 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005828static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005829{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005830 REQP firstp, lastp;
5831 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005833 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5834 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005836 /*
5837 * If 'tid' is not ASC_TID_ALL, return requests only for
5838 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
5839 * requests for all tids.
5840 */
5841 if (tid != ASC_TID_ALL) {
5842 /* Return all requests for the specified 'tid'. */
5843 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
5844 /* List is empty; Set first and last return pointers to NULL. */
5845 firstp = lastp = NULL;
5846 } else {
5847 firstp = ascq->q_first[tid];
5848 lastp = ascq->q_last[tid];
5849 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
5850 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005852 {
5853 REQP reqp;
5854 ascq->q_cur_cnt[tid] = 0;
5855 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5856 REQTIMESTAT("asc_dequeue_list", ascq,
5857 reqp, tid);
5858 }
5859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005861 }
5862 } else {
5863 /* Return all requests for all tids. */
5864 firstp = lastp = NULL;
5865 for (i = 0; i <= ADV_MAX_TID; i++) {
5866 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
5867 if (firstp == NULL) {
5868 firstp = ascq->q_first[i];
5869 lastp = ascq->q_last[i];
5870 } else {
5871 ASC_ASSERT(lastp != NULL);
5872 lastp->host_scribble =
5873 (unsigned char *)ascq->q_first[i];
5874 lastp = ascq->q_last[i];
5875 }
5876 ascq->q_first[i] = ascq->q_last[i] = NULL;
5877 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005879 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005881 }
5882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005884 {
5885 REQP reqp;
5886 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5887 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
5888 reqp->device->id);
5889 }
5890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005892 }
5893 if (lastpp) {
5894 *lastpp = lastp;
5895 }
5896 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
5897 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898}
5899
5900/*
5901 * Remove the specified 'REQP' from the specified queue for
5902 * the specified target device. Clear the 'tidmask' bit for the
5903 * device if no more commands are left queued for it.
5904 *
5905 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
5906 *
5907 * Return ASC_TRUE if the command was found and removed,
5908 * otherwise return ASC_FALSE.
5909 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005910static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005912 REQP currp, prevp;
5913 int tid;
5914 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005916 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
5917 (ulong)ascq, (ulong)reqp);
5918 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005920 tid = REQPTID(reqp);
5921 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005923 /*
5924 * Handle the common case of 'reqp' being the first
5925 * entry on the queue.
5926 */
5927 if (reqp == ascq->q_first[tid]) {
5928 ret = ASC_TRUE;
5929 ascq->q_first[tid] = REQPNEXT(reqp);
5930 /* If the queue is now empty, clear its bit and the last pointer. */
5931 if (ascq->q_first[tid] == NULL) {
5932 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5933 ASC_ASSERT(ascq->q_last[tid] == reqp);
5934 ascq->q_last[tid] = NULL;
5935 }
5936 } else if (ascq->q_first[tid] != NULL) {
5937 ASC_ASSERT(ascq->q_last[tid] != NULL);
5938 /*
5939 * Because the case of 'reqp' being the first entry has been
5940 * handled above and it is known the queue is not empty, if
5941 * 'reqp' is found on the queue it is guaranteed the queue will
5942 * not become empty and that 'q_first[tid]' will not be changed.
5943 *
5944 * Set 'prevp' to the first entry, 'currp' to the second entry,
5945 * and search for 'reqp'.
5946 */
5947 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
5948 currp; prevp = currp, currp = REQPNEXT(currp)) {
5949 if (currp == reqp) {
5950 ret = ASC_TRUE;
5951 prevp->host_scribble =
5952 (unsigned char *)REQPNEXT(currp);
5953 reqp->host_scribble = NULL;
5954 if (ascq->q_last[tid] == reqp) {
5955 ascq->q_last[tid] = prevp;
5956 }
5957 break;
5958 }
5959 }
5960 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005962 /* Maintain request queue statistics. */
5963 if (ret == ASC_TRUE) {
5964 ascq->q_cur_cnt[tid]--;
5965 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
5966 }
5967 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005969 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
5970 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971}
5972
5973/*
5974 * Execute as many queued requests as possible for the specified queue.
5975 *
5976 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
5977 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005978static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005980 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
5981 REQP reqp;
5982 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005984 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
5985 /*
5986 * Execute queued commands for devices attached to
5987 * the current board in round-robin fashion.
5988 */
5989 scan_tidmask = ascq->q_tidmask;
5990 do {
5991 for (i = 0; i <= ADV_MAX_TID; i++) {
5992 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
5993 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
5994 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
5995 } else
5996 if (asc_execute_scsi_cmnd
5997 ((struct scsi_cmnd *)reqp)
5998 == ASC_BUSY) {
5999 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6000 /*
6001 * The request returned ASC_BUSY. Enqueue at the front of
6002 * target's waiting list to maintain correct ordering.
6003 */
6004 asc_enqueue(ascq, reqp, ASC_FRONT);
6005 }
6006 }
6007 }
6008 } while (scan_tidmask);
6009 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010}
6011
6012#ifdef CONFIG_PROC_FS
6013/*
6014 * asc_prt_board_devices()
6015 *
6016 * Print driver information for devices attached to the board.
6017 *
6018 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6019 * cf. asc_prt_line().
6020 *
6021 * Return the number of characters copied into 'cp'. No more than
6022 * 'cplen' characters will be copied to 'cp'.
6023 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006024static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006026 asc_board_t *boardp;
6027 int leftlen;
6028 int totlen;
6029 int len;
6030 int chip_scsi_id;
6031 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006033 boardp = ASC_BOARDP(shost);
6034 leftlen = cplen;
6035 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006037 len = asc_prt_line(cp, leftlen,
6038 "\nDevice Information for AdvanSys SCSI Host %d:\n",
6039 shost->host_no);
6040 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006042 if (ASC_NARROW_BOARD(boardp)) {
6043 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6044 } else {
6045 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006048 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6049 ASC_PRT_NEXT();
6050 for (i = 0; i <= ADV_MAX_TID; i++) {
6051 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6052 len = asc_prt_line(cp, leftlen, " %X,", i);
6053 ASC_PRT_NEXT();
6054 }
6055 }
6056 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6057 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006058
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006059 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060}
6061
6062/*
6063 * Display Wide Board BIOS Information.
6064 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006065static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006067 asc_board_t *boardp;
6068 int leftlen;
6069 int totlen;
6070 int len;
6071 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006073 boardp = ASC_BOARDP(shost);
6074 leftlen = cplen;
6075 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006077 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6078 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006080 /*
6081 * If the BIOS saved a valid signature, then fill in
6082 * the BIOS code segment base address.
6083 */
6084 if (boardp->bios_signature != 0x55AA) {
6085 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6086 ASC_PRT_NEXT();
6087 len = asc_prt_line(cp, leftlen,
6088 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6089 ASC_PRT_NEXT();
6090 len = asc_prt_line(cp, leftlen,
6091 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6092 ASC_PRT_NEXT();
6093 } else {
6094 major = (boardp->bios_version >> 12) & 0xF;
6095 minor = (boardp->bios_version >> 8) & 0xF;
6096 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006098 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6099 major, minor,
6100 letter >= 26 ? '?' : letter + 'A');
6101 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006103 /*
6104 * Current available ROM BIOS release is 3.1I for UW
6105 * and 3.2I for U2W. This code doesn't differentiate
6106 * UW and U2W boards.
6107 */
6108 if (major < 3 || (major <= 3 && minor < 1) ||
6109 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6110 len = asc_prt_line(cp, leftlen,
6111 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6112 ASC_PRT_NEXT();
6113 len = asc_prt_line(cp, leftlen,
6114 "ftp://ftp.connectcom.net/pub\n");
6115 ASC_PRT_NEXT();
6116 }
6117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006119 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120}
6121
6122/*
6123 * Add serial number to information bar if signature AAh
6124 * is found in at bit 15-9 (7 bits) of word 1.
6125 *
6126 * Serial Number consists fo 12 alpha-numeric digits.
6127 *
6128 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6129 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6130 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6131 * 5 - Product revision (A-J) Word0: " "
6132 *
6133 * Signature Word1: 15-9 (7 bits)
6134 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6135 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6136 *
6137 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6138 *
6139 * Note 1: Only production cards will have a serial number.
6140 *
6141 * Note 2: Signature is most significant 7 bits (0xFE).
6142 *
6143 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6144 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006145static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006147 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006149 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6150 return ASC_FALSE;
6151 } else {
6152 /*
6153 * First word - 6 digits.
6154 */
6155 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006157 /* Product type - 1st digit. */
6158 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6159 /* Product type is P=Prototype */
6160 *cp += 0x8;
6161 }
6162 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006164 /* Manufacturing location - 2nd digit. */
6165 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006167 /* Product ID - 3rd, 4th digits. */
6168 num = w & 0x3FF;
6169 *cp++ = '0' + (num / 100);
6170 num %= 100;
6171 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006173 /* Product revision - 5th digit. */
6174 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006175
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006176 /*
6177 * Second word
6178 */
6179 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006181 /*
6182 * Year - 6th digit.
6183 *
6184 * If bit 15 of third word is set, then the
6185 * last digit of the year is greater than 7.
6186 */
6187 if (serialnum[2] & 0x8000) {
6188 *cp++ = '8' + ((w & 0x1C0) >> 6);
6189 } else {
6190 *cp++ = '0' + ((w & 0x1C0) >> 6);
6191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006193 /* Week of year - 7th, 8th digits. */
6194 num = w & 0x003F;
6195 *cp++ = '0' + num / 10;
6196 num %= 10;
6197 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006199 /*
6200 * Third word
6201 */
6202 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006203
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006204 /* Serial number - 9th digit. */
6205 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006207 /* 10th, 11th, 12th digits. */
6208 num = w % 1000;
6209 *cp++ = '0' + num / 100;
6210 num %= 100;
6211 *cp++ = '0' + num / 10;
6212 num %= 10;
6213 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006215 *cp = '\0'; /* Null Terminate the string. */
6216 return ASC_TRUE;
6217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218}
6219
6220/*
6221 * asc_prt_asc_board_eeprom()
6222 *
6223 * Print board EEPROM configuration.
6224 *
6225 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6226 * cf. asc_prt_line().
6227 *
6228 * Return the number of characters copied into 'cp'. No more than
6229 * 'cplen' characters will be copied to 'cp'.
6230 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006231static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006233 asc_board_t *boardp;
6234 ASC_DVC_VAR *asc_dvc_varp;
6235 int leftlen;
6236 int totlen;
6237 int len;
6238 ASCEEP_CONFIG *ep;
6239 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006241 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006243 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006245 boardp = ASC_BOARDP(shost);
6246 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6247 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006249 leftlen = cplen;
6250 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006252 len = asc_prt_line(cp, leftlen,
6253 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6254 shost->host_no);
6255 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006257 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6258 == ASC_TRUE) {
6259 len =
6260 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6261 serialstr);
6262 ASC_PRT_NEXT();
6263 } else {
6264 if (ep->adapter_info[5] == 0xBB) {
6265 len = asc_prt_line(cp, leftlen,
6266 " Default Settings Used for EEPROM-less Adapter.\n");
6267 ASC_PRT_NEXT();
6268 } else {
6269 len = asc_prt_line(cp, leftlen,
6270 " Serial Number Signature Not Present.\n");
6271 ASC_PRT_NEXT();
6272 }
6273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006275 len = asc_prt_line(cp, leftlen,
6276 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6277 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6278 ep->max_tag_qng);
6279 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006280
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006281 len = asc_prt_line(cp, leftlen,
6282 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6283 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006285 len = asc_prt_line(cp, leftlen, " Target ID: ");
6286 ASC_PRT_NEXT();
6287 for (i = 0; i <= ASC_MAX_TID; i++) {
6288 len = asc_prt_line(cp, leftlen, " %d", i);
6289 ASC_PRT_NEXT();
6290 }
6291 len = asc_prt_line(cp, leftlen, "\n");
6292 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006294 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6295 ASC_PRT_NEXT();
6296 for (i = 0; i <= ASC_MAX_TID; i++) {
6297 len = asc_prt_line(cp, leftlen, " %c",
6298 (ep->
6299 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6300 'N');
6301 ASC_PRT_NEXT();
6302 }
6303 len = asc_prt_line(cp, leftlen, "\n");
6304 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006306 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6307 ASC_PRT_NEXT();
6308 for (i = 0; i <= ASC_MAX_TID; i++) {
6309 len = asc_prt_line(cp, leftlen, " %c",
6310 (ep->
6311 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6312 'N');
6313 ASC_PRT_NEXT();
6314 }
6315 len = asc_prt_line(cp, leftlen, "\n");
6316 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006318 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6319 ASC_PRT_NEXT();
6320 for (i = 0; i <= ASC_MAX_TID; i++) {
6321 len = asc_prt_line(cp, leftlen, " %c",
6322 (ep->
6323 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6324 'N');
6325 ASC_PRT_NEXT();
6326 }
6327 len = asc_prt_line(cp, leftlen, "\n");
6328 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006329
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006330 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6331 ASC_PRT_NEXT();
6332 for (i = 0; i <= ASC_MAX_TID; i++) {
6333 len = asc_prt_line(cp, leftlen, " %c",
6334 (ep->
6335 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6336 'N');
6337 ASC_PRT_NEXT();
6338 }
6339 len = asc_prt_line(cp, leftlen, "\n");
6340 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341
6342#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006343 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6344 len = asc_prt_line(cp, leftlen,
6345 " Host ISA DMA speed: %d MB/S\n",
6346 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6347 ASC_PRT_NEXT();
6348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349#endif /* CONFIG_ISA */
6350
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006351 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352}
6353
6354/*
6355 * asc_prt_adv_board_eeprom()
6356 *
6357 * Print board EEPROM configuration.
6358 *
6359 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6360 * cf. asc_prt_line().
6361 *
6362 * Return the number of characters copied into 'cp'. No more than
6363 * 'cplen' characters will be copied to 'cp'.
6364 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006365static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006366{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006367 asc_board_t *boardp;
6368 ADV_DVC_VAR *adv_dvc_varp;
6369 int leftlen;
6370 int totlen;
6371 int len;
6372 int i;
6373 char *termstr;
6374 uchar serialstr[13];
6375 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6376 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6377 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6378 ushort word;
6379 ushort *wordp;
6380 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006382 boardp = ASC_BOARDP(shost);
6383 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6384 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6385 ep_3550 = &boardp->eep_config.adv_3550_eep;
6386 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6387 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6388 } else {
6389 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006392 leftlen = cplen;
6393 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006395 len = asc_prt_line(cp, leftlen,
6396 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6397 shost->host_no);
6398 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006400 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6401 wordp = &ep_3550->serial_number_word1;
6402 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6403 wordp = &ep_38C0800->serial_number_word1;
6404 } else {
6405 wordp = &ep_38C1600->serial_number_word1;
6406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006408 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6409 len =
6410 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6411 serialstr);
6412 ASC_PRT_NEXT();
6413 } else {
6414 len = asc_prt_line(cp, leftlen,
6415 " Serial Number Signature Not Present.\n");
6416 ASC_PRT_NEXT();
6417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006418
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006419 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6420 len = asc_prt_line(cp, leftlen,
6421 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6422 ep_3550->adapter_scsi_id,
6423 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6424 ASC_PRT_NEXT();
6425 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6426 len = asc_prt_line(cp, leftlen,
6427 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6428 ep_38C0800->adapter_scsi_id,
6429 ep_38C0800->max_host_qng,
6430 ep_38C0800->max_dvc_qng);
6431 ASC_PRT_NEXT();
6432 } else {
6433 len = asc_prt_line(cp, leftlen,
6434 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6435 ep_38C1600->adapter_scsi_id,
6436 ep_38C1600->max_host_qng,
6437 ep_38C1600->max_dvc_qng);
6438 ASC_PRT_NEXT();
6439 }
6440 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6441 word = ep_3550->termination;
6442 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6443 word = ep_38C0800->termination_lvd;
6444 } else {
6445 word = ep_38C1600->termination_lvd;
6446 }
6447 switch (word) {
6448 case 1:
6449 termstr = "Low Off/High Off";
6450 break;
6451 case 2:
6452 termstr = "Low Off/High On";
6453 break;
6454 case 3:
6455 termstr = "Low On/High On";
6456 break;
6457 default:
6458 case 0:
6459 termstr = "Automatic";
6460 break;
6461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006462
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006463 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6464 len = asc_prt_line(cp, leftlen,
6465 " termination: %u (%s), bios_ctrl: 0x%x\n",
6466 ep_3550->termination, termstr,
6467 ep_3550->bios_ctrl);
6468 ASC_PRT_NEXT();
6469 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6470 len = asc_prt_line(cp, leftlen,
6471 " termination: %u (%s), bios_ctrl: 0x%x\n",
6472 ep_38C0800->termination_lvd, termstr,
6473 ep_38C0800->bios_ctrl);
6474 ASC_PRT_NEXT();
6475 } else {
6476 len = asc_prt_line(cp, leftlen,
6477 " termination: %u (%s), bios_ctrl: 0x%x\n",
6478 ep_38C1600->termination_lvd, termstr,
6479 ep_38C1600->bios_ctrl);
6480 ASC_PRT_NEXT();
6481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006482
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006483 len = asc_prt_line(cp, leftlen, " Target ID: ");
6484 ASC_PRT_NEXT();
6485 for (i = 0; i <= ADV_MAX_TID; i++) {
6486 len = asc_prt_line(cp, leftlen, " %X", i);
6487 ASC_PRT_NEXT();
6488 }
6489 len = asc_prt_line(cp, leftlen, "\n");
6490 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006492 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6493 word = ep_3550->disc_enable;
6494 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6495 word = ep_38C0800->disc_enable;
6496 } else {
6497 word = ep_38C1600->disc_enable;
6498 }
6499 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6500 ASC_PRT_NEXT();
6501 for (i = 0; i <= ADV_MAX_TID; i++) {
6502 len = asc_prt_line(cp, leftlen, " %c",
6503 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6504 ASC_PRT_NEXT();
6505 }
6506 len = asc_prt_line(cp, leftlen, "\n");
6507 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006508
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006509 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6510 word = ep_3550->tagqng_able;
6511 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6512 word = ep_38C0800->tagqng_able;
6513 } else {
6514 word = ep_38C1600->tagqng_able;
6515 }
6516 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6517 ASC_PRT_NEXT();
6518 for (i = 0; i <= ADV_MAX_TID; i++) {
6519 len = asc_prt_line(cp, leftlen, " %c",
6520 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6521 ASC_PRT_NEXT();
6522 }
6523 len = asc_prt_line(cp, leftlen, "\n");
6524 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006525
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006526 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6527 word = ep_3550->start_motor;
6528 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6529 word = ep_38C0800->start_motor;
6530 } else {
6531 word = ep_38C1600->start_motor;
6532 }
6533 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6534 ASC_PRT_NEXT();
6535 for (i = 0; i <= ADV_MAX_TID; i++) {
6536 len = asc_prt_line(cp, leftlen, " %c",
6537 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6538 ASC_PRT_NEXT();
6539 }
6540 len = asc_prt_line(cp, leftlen, "\n");
6541 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006542
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006543 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6544 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6545 ASC_PRT_NEXT();
6546 for (i = 0; i <= ADV_MAX_TID; i++) {
6547 len = asc_prt_line(cp, leftlen, " %c",
6548 (ep_3550->
6549 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6550 'Y' : 'N');
6551 ASC_PRT_NEXT();
6552 }
6553 len = asc_prt_line(cp, leftlen, "\n");
6554 ASC_PRT_NEXT();
6555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006556
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006557 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6558 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6559 ASC_PRT_NEXT();
6560 for (i = 0; i <= ADV_MAX_TID; i++) {
6561 len = asc_prt_line(cp, leftlen, " %c",
6562 (ep_3550->
6563 ultra_able & ADV_TID_TO_TIDMASK(i))
6564 ? 'Y' : 'N');
6565 ASC_PRT_NEXT();
6566 }
6567 len = asc_prt_line(cp, leftlen, "\n");
6568 ASC_PRT_NEXT();
6569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006570
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006571 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6572 word = ep_3550->wdtr_able;
6573 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6574 word = ep_38C0800->wdtr_able;
6575 } else {
6576 word = ep_38C1600->wdtr_able;
6577 }
6578 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6579 ASC_PRT_NEXT();
6580 for (i = 0; i <= ADV_MAX_TID; i++) {
6581 len = asc_prt_line(cp, leftlen, " %c",
6582 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6583 ASC_PRT_NEXT();
6584 }
6585 len = asc_prt_line(cp, leftlen, "\n");
6586 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006587
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006588 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6589 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6590 len = asc_prt_line(cp, leftlen,
6591 " Synchronous Transfer Speed (Mhz):\n ");
6592 ASC_PRT_NEXT();
6593 for (i = 0; i <= ADV_MAX_TID; i++) {
6594 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006595
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006596 if (i == 0) {
6597 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6598 } else if (i == 4) {
6599 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6600 } else if (i == 8) {
6601 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6602 } else if (i == 12) {
6603 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6604 }
6605 switch (sdtr_speed & ADV_MAX_TID) {
6606 case 0:
6607 speed_str = "Off";
6608 break;
6609 case 1:
6610 speed_str = " 5";
6611 break;
6612 case 2:
6613 speed_str = " 10";
6614 break;
6615 case 3:
6616 speed_str = " 20";
6617 break;
6618 case 4:
6619 speed_str = " 40";
6620 break;
6621 case 5:
6622 speed_str = " 80";
6623 break;
6624 default:
6625 speed_str = "Unk";
6626 break;
6627 }
6628 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6629 ASC_PRT_NEXT();
6630 if (i == 7) {
6631 len = asc_prt_line(cp, leftlen, "\n ");
6632 ASC_PRT_NEXT();
6633 }
6634 sdtr_speed >>= 4;
6635 }
6636 len = asc_prt_line(cp, leftlen, "\n");
6637 ASC_PRT_NEXT();
6638 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006639
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006640 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006641}
6642
6643/*
6644 * asc_prt_driver_conf()
6645 *
6646 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6647 * cf. asc_prt_line().
6648 *
6649 * Return the number of characters copied into 'cp'. No more than
6650 * 'cplen' characters will be copied to 'cp'.
6651 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006652static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006653{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006654 asc_board_t *boardp;
6655 int leftlen;
6656 int totlen;
6657 int len;
6658 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006659
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006660 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006661
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006662 leftlen = cplen;
6663 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006664
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006665 len = asc_prt_line(cp, leftlen,
6666 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6667 shost->host_no);
6668 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006670 len = asc_prt_line(cp, leftlen,
6671 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6672 shost->host_busy, shost->last_reset, shost->max_id,
6673 shost->max_lun, shost->max_channel);
6674 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006676 len = asc_prt_line(cp, leftlen,
6677 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6678 shost->unique_id, shost->can_queue, shost->this_id,
6679 shost->sg_tablesize, shost->cmd_per_lun);
6680 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006682 len = asc_prt_line(cp, leftlen,
6683 " unchecked_isa_dma %d, use_clustering %d\n",
6684 shost->unchecked_isa_dma, shost->use_clustering);
6685 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006686
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006687 len = asc_prt_line(cp, leftlen,
6688 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6689 boardp->flags, boardp->last_reset, jiffies,
6690 boardp->asc_n_io_port);
6691 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006692
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04006693 len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006694 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006696 if (ASC_NARROW_BOARD(boardp)) {
6697 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6698 } else {
6699 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006701
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006702 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006703}
6704
6705/*
6706 * asc_prt_asc_board_info()
6707 *
6708 * Print dynamic board configuration information.
6709 *
6710 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6711 * cf. asc_prt_line().
6712 *
6713 * Return the number of characters copied into 'cp'. No more than
6714 * 'cplen' characters will be copied to 'cp'.
6715 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006716static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006717{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006718 asc_board_t *boardp;
6719 int chip_scsi_id;
6720 int leftlen;
6721 int totlen;
6722 int len;
6723 ASC_DVC_VAR *v;
6724 ASC_DVC_CFG *c;
6725 int i;
6726 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006727
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006728 boardp = ASC_BOARDP(shost);
6729 v = &boardp->dvc_var.asc_dvc_var;
6730 c = &boardp->dvc_cfg.asc_dvc_cfg;
6731 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006732
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006733 leftlen = cplen;
6734 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006736 len = asc_prt_line(cp, leftlen,
6737 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6738 shost->host_no);
6739 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006740
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006741 len = asc_prt_line(cp, leftlen,
6742 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6743 c->chip_version, c->lib_version, c->lib_serial_no,
6744 c->mcode_date);
6745 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006746
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006747 len = asc_prt_line(cp, leftlen,
6748 " mcode_version 0x%x, err_code %u\n",
6749 c->mcode_version, v->err_code);
6750 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006752 /* Current number of commands waiting for the host. */
6753 len = asc_prt_line(cp, leftlen,
6754 " Total Command Pending: %d\n", v->cur_total_qng);
6755 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006756
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006757 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6758 ASC_PRT_NEXT();
6759 for (i = 0; i <= ASC_MAX_TID; i++) {
6760 if ((chip_scsi_id == i) ||
6761 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6762 continue;
6763 }
6764 len = asc_prt_line(cp, leftlen, " %X:%c",
6765 i,
6766 (v->
6767 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6768 'Y' : 'N');
6769 ASC_PRT_NEXT();
6770 }
6771 len = asc_prt_line(cp, leftlen, "\n");
6772 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006773
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006774 /* Current number of commands waiting for a device. */
6775 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6776 ASC_PRT_NEXT();
6777 for (i = 0; i <= ASC_MAX_TID; i++) {
6778 if ((chip_scsi_id == i) ||
6779 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6780 continue;
6781 }
6782 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6783 ASC_PRT_NEXT();
6784 }
6785 len = asc_prt_line(cp, leftlen, "\n");
6786 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006787
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006788 /* Current limit on number of commands that can be sent to a device. */
6789 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6790 ASC_PRT_NEXT();
6791 for (i = 0; i <= ASC_MAX_TID; i++) {
6792 if ((chip_scsi_id == i) ||
6793 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6794 continue;
6795 }
6796 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
6797 ASC_PRT_NEXT();
6798 }
6799 len = asc_prt_line(cp, leftlen, "\n");
6800 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006801
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006802 /* Indicate whether the device has returned queue full status. */
6803 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
6804 ASC_PRT_NEXT();
6805 for (i = 0; i <= ASC_MAX_TID; i++) {
6806 if ((chip_scsi_id == i) ||
6807 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6808 continue;
6809 }
6810 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
6811 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
6812 i, boardp->queue_full_cnt[i]);
6813 } else {
6814 len = asc_prt_line(cp, leftlen, " %X:N", i);
6815 }
6816 ASC_PRT_NEXT();
6817 }
6818 len = asc_prt_line(cp, leftlen, "\n");
6819 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006820
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006821 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6822 ASC_PRT_NEXT();
6823 for (i = 0; i <= ASC_MAX_TID; i++) {
6824 if ((chip_scsi_id == i) ||
6825 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6826 continue;
6827 }
6828 len = asc_prt_line(cp, leftlen, " %X:%c",
6829 i,
6830 (v->
6831 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6832 'N');
6833 ASC_PRT_NEXT();
6834 }
6835 len = asc_prt_line(cp, leftlen, "\n");
6836 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006837
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006838 for (i = 0; i <= ASC_MAX_TID; i++) {
6839 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006840
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006841 if ((chip_scsi_id == i) ||
6842 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6843 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
6844 continue;
6845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006846
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006847 len = asc_prt_line(cp, leftlen, " %X:", i);
6848 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006850 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
6851 len = asc_prt_line(cp, leftlen, " Asynchronous");
6852 ASC_PRT_NEXT();
6853 } else {
6854 syn_period_ix =
6855 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
6856 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006858 len = asc_prt_line(cp, leftlen,
6859 " Transfer Period Factor: %d (%d.%d Mhz),",
6860 v->sdtr_period_tbl[syn_period_ix],
6861 250 /
6862 v->sdtr_period_tbl[syn_period_ix],
6863 ASC_TENTHS(250,
6864 v->
6865 sdtr_period_tbl
6866 [syn_period_ix]));
6867 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006868
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006869 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6870 boardp->
6871 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
6872 ASC_PRT_NEXT();
6873 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006874
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006875 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6876 len = asc_prt_line(cp, leftlen, "*\n");
6877 renegotiate = 1;
6878 } else {
6879 len = asc_prt_line(cp, leftlen, "\n");
6880 }
6881 ASC_PRT_NEXT();
6882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006883
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006884 if (renegotiate) {
6885 len = asc_prt_line(cp, leftlen,
6886 " * = Re-negotiation pending before next command.\n");
6887 ASC_PRT_NEXT();
6888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006889
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006890 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006891}
6892
6893/*
6894 * asc_prt_adv_board_info()
6895 *
6896 * Print dynamic board configuration information.
6897 *
6898 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6899 * cf. asc_prt_line().
6900 *
6901 * Return the number of characters copied into 'cp'. No more than
6902 * 'cplen' characters will be copied to 'cp'.
6903 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006904static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006905{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006906 asc_board_t *boardp;
6907 int leftlen;
6908 int totlen;
6909 int len;
6910 int i;
6911 ADV_DVC_VAR *v;
6912 ADV_DVC_CFG *c;
6913 AdvPortAddr iop_base;
6914 ushort chip_scsi_id;
6915 ushort lramword;
6916 uchar lrambyte;
6917 ushort tagqng_able;
6918 ushort sdtr_able, wdtr_able;
6919 ushort wdtr_done, sdtr_done;
6920 ushort period = 0;
6921 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006922
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006923 boardp = ASC_BOARDP(shost);
6924 v = &boardp->dvc_var.adv_dvc_var;
6925 c = &boardp->dvc_cfg.adv_dvc_cfg;
6926 iop_base = v->iop_base;
6927 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006929 leftlen = cplen;
6930 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006931
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006932 len = asc_prt_line(cp, leftlen,
6933 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6934 shost->host_no);
6935 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006936
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006937 len = asc_prt_line(cp, leftlen,
6938 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
6939 v->iop_base,
6940 AdvReadWordRegister(iop_base,
6941 IOPW_SCSI_CFG1) & CABLE_DETECT,
6942 v->err_code);
6943 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006944
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006945 len = asc_prt_line(cp, leftlen,
6946 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
6947 c->chip_version, c->lib_version, c->mcode_date,
6948 c->mcode_version);
6949 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006950
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006951 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
6952 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
6953 ASC_PRT_NEXT();
6954 for (i = 0; i <= ADV_MAX_TID; i++) {
6955 if ((chip_scsi_id == i) ||
6956 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6957 continue;
6958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006959
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006960 len = asc_prt_line(cp, leftlen, " %X:%c",
6961 i,
6962 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6963 'N');
6964 ASC_PRT_NEXT();
6965 }
6966 len = asc_prt_line(cp, leftlen, "\n");
6967 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006968
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006969 len = asc_prt_line(cp, leftlen, " Queue Limit:");
6970 ASC_PRT_NEXT();
6971 for (i = 0; i <= ADV_MAX_TID; i++) {
6972 if ((chip_scsi_id == i) ||
6973 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6974 continue;
6975 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006976
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006977 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
6978 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006979
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006980 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6981 ASC_PRT_NEXT();
6982 }
6983 len = asc_prt_line(cp, leftlen, "\n");
6984 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006985
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006986 len = asc_prt_line(cp, leftlen, " Command Pending:");
6987 ASC_PRT_NEXT();
6988 for (i = 0; i <= ADV_MAX_TID; i++) {
6989 if ((chip_scsi_id == i) ||
6990 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6991 continue;
6992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006993
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006994 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
6995 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006997 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6998 ASC_PRT_NEXT();
6999 }
7000 len = asc_prt_line(cp, leftlen, "\n");
7001 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007002
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007003 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
7004 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
7005 ASC_PRT_NEXT();
7006 for (i = 0; i <= ADV_MAX_TID; i++) {
7007 if ((chip_scsi_id == i) ||
7008 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7009 continue;
7010 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007011
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007012 len = asc_prt_line(cp, leftlen, " %X:%c",
7013 i,
7014 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7015 'N');
7016 ASC_PRT_NEXT();
7017 }
7018 len = asc_prt_line(cp, leftlen, "\n");
7019 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007020
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007021 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
7022 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
7023 ASC_PRT_NEXT();
7024 for (i = 0; i <= ADV_MAX_TID; i++) {
7025 if ((chip_scsi_id == i) ||
7026 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7027 continue;
7028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007029
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007030 AdvReadWordLram(iop_base,
7031 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7032 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007033
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007034 len = asc_prt_line(cp, leftlen, " %X:%d",
7035 i, (lramword & 0x8000) ? 16 : 8);
7036 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007037
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007038 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
7039 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7040 len = asc_prt_line(cp, leftlen, "*");
7041 ASC_PRT_NEXT();
7042 renegotiate = 1;
7043 }
7044 }
7045 len = asc_prt_line(cp, leftlen, "\n");
7046 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007048 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7049 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7050 ASC_PRT_NEXT();
7051 for (i = 0; i <= ADV_MAX_TID; i++) {
7052 if ((chip_scsi_id == i) ||
7053 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7054 continue;
7055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007056
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007057 len = asc_prt_line(cp, leftlen, " %X:%c",
7058 i,
7059 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7060 'N');
7061 ASC_PRT_NEXT();
7062 }
7063 len = asc_prt_line(cp, leftlen, "\n");
7064 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007065
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007066 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7067 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007068
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007069 AdvReadWordLram(iop_base,
7070 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7071 lramword);
7072 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007073
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007074 if ((chip_scsi_id == i) ||
7075 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7076 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7077 continue;
7078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007080 len = asc_prt_line(cp, leftlen, " %X:", i);
7081 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007083 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7084 len = asc_prt_line(cp, leftlen, " Asynchronous");
7085 ASC_PRT_NEXT();
7086 } else {
7087 len =
7088 asc_prt_line(cp, leftlen,
7089 " Transfer Period Factor: ");
7090 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007091
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007092 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7093 len =
7094 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7095 ASC_PRT_NEXT();
7096 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7097 len =
7098 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7099 ASC_PRT_NEXT();
7100 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007101
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007102 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007103
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007104 if (period == 0) { /* Should never happen. */
7105 len =
7106 asc_prt_line(cp, leftlen,
7107 "%d (? Mhz), ");
7108 ASC_PRT_NEXT();
7109 } else {
7110 len = asc_prt_line(cp, leftlen,
7111 "%d (%d.%d Mhz),",
7112 period, 250 / period,
7113 ASC_TENTHS(250,
7114 period));
7115 ASC_PRT_NEXT();
7116 }
7117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007118
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007119 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7120 lramword & 0x1F);
7121 ASC_PRT_NEXT();
7122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007123
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007124 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7125 len = asc_prt_line(cp, leftlen, "*\n");
7126 renegotiate = 1;
7127 } else {
7128 len = asc_prt_line(cp, leftlen, "\n");
7129 }
7130 ASC_PRT_NEXT();
7131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007132
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007133 if (renegotiate) {
7134 len = asc_prt_line(cp, leftlen,
7135 " * = Re-negotiation pending before next command.\n");
7136 ASC_PRT_NEXT();
7137 }
7138
7139 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007140}
7141
7142/*
7143 * asc_proc_copy()
7144 *
7145 * Copy proc information to a read buffer taking into account the current
7146 * read offset in the file and the remaining space in the read buffer.
7147 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007148static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007149asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007150 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007151{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007152 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007154 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7155 (unsigned)offset, (unsigned)advoffset, cplen);
7156 if (offset <= advoffset) {
7157 /* Read offset below current offset, copy everything. */
7158 cnt = min(cplen, leftlen);
7159 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7160 (ulong)curbuf, (ulong)cp, cnt);
7161 memcpy(curbuf, cp, cnt);
7162 } else if (offset < advoffset + cplen) {
7163 /* Read offset within current range, partial copy. */
7164 cnt = (advoffset + cplen) - offset;
7165 cp = (cp + cplen) - cnt;
7166 cnt = min(cnt, leftlen);
7167 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7168 (ulong)curbuf, (ulong)cp, cnt);
7169 memcpy(curbuf, cp, cnt);
7170 }
7171 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007172}
7173
7174/*
7175 * asc_prt_line()
7176 *
7177 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7178 *
7179 * Return 0 if printing to the console, otherwise return the number of
7180 * bytes written to the buffer.
7181 *
7182 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7183 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7184 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007185static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007186{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007187 va_list args;
7188 int ret;
7189 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007190
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007191 va_start(args, fmt);
7192 ret = vsprintf(s, fmt, args);
7193 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7194 if (buf == NULL) {
7195 (void)printk(s);
7196 ret = 0;
7197 } else {
7198 ret = min(buflen, ret);
7199 memcpy(buf, s, ret);
7200 }
7201 va_end(args);
7202 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007203}
7204#endif /* CONFIG_PROC_FS */
7205
Linus Torvalds1da177e2005-04-16 15:20:36 -07007206/*
7207 * --- Functions Required by the Asc Library
7208 */
7209
7210/*
7211 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7212 * global variable which is incremented once every 5 ms
7213 * from a timer interrupt, because this function may be
7214 * called when interrupts are disabled.
7215 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007216static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007217{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007218 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7219 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007220}
7221
7222/*
7223 * Currently and inline noop but leave as a placeholder.
7224 * Leave DvcEnterCritical() as a noop placeholder.
7225 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007226static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007227{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007228 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007229}
7230
7231/*
7232 * Critical sections are all protected by the board spinlock.
7233 * Leave DvcLeaveCritical() as a noop placeholder.
7234 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007235static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007236{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007237 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007238}
7239
7240/*
7241 * void
7242 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7243 *
7244 * Calling/Exit State:
7245 * none
7246 *
7247 * Description:
7248 * Output an ASC_SCSI_Q structure to the chip
7249 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007250static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007251DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7252{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007253 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007254
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007255 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7256 AscSetChipLramAddr(iop_base, s_addr);
7257 for (i = 0; i < 2 * words; i += 2) {
7258 if (i == 4 || i == 20) {
7259 continue;
7260 }
7261 outpw(iop_base + IOP_RAM_DATA,
7262 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007264}
7265
7266/*
7267 * void
7268 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7269 *
7270 * Calling/Exit State:
7271 * none
7272 *
7273 * Description:
7274 * Input an ASC_QDONE_INFO structure from the chip
7275 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007276static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007277DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7278{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007279 int i;
7280 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007281
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007282 AscSetChipLramAddr(iop_base, s_addr);
7283 for (i = 0; i < 2 * words; i += 2) {
7284 if (i == 10) {
7285 continue;
7286 }
7287 word = inpw(iop_base + IOP_RAM_DATA);
7288 inbuf[i] = word & 0xff;
7289 inbuf[i + 1] = (word >> 8) & 0xff;
7290 }
7291 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007292}
7293
7294/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007295 * Return the BIOS address of the adapter at the specified
7296 * I/O port and with the specified bus type.
7297 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007298static unsigned short __devinit
7299AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007300{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007301 unsigned short cfg_lsw;
7302 unsigned short bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007303
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007304 /*
7305 * The PCI BIOS is re-located by the motherboard BIOS. Because
7306 * of this the driver can not determine where a PCI BIOS is
7307 * loaded and executes.
7308 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007309 if (bus_type & ASC_IS_PCI)
7310 return 0;
7311
Linus Torvalds1da177e2005-04-16 15:20:36 -07007312#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007313 if ((bus_type & ASC_IS_EISA) != 0) {
7314 cfg_lsw = AscGetEisaChipCfg(iop_base);
7315 cfg_lsw &= 0x000F;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007316 bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
7317 return bios_addr;
7318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007319#endif /* CONFIG_ISA */
7320
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007321 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007322
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007323 /*
7324 * ISA PnP uses the top bit as the 32K BIOS flag
7325 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007326 if (bus_type == ASC_IS_ISAPNP)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007327 cfg_lsw &= 0x7FFF;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007328 bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
7329 return bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007330}
7331
Linus Torvalds1da177e2005-04-16 15:20:36 -07007332/*
7333 * --- Functions Required by the Adv Library
7334 */
7335
7336/*
7337 * DvcGetPhyAddr()
7338 *
7339 * Return the physical address of 'vaddr' and set '*lenp' to the
7340 * number of physically contiguous bytes that follow 'vaddr'.
7341 * 'flag' indicates the type of structure whose physical address
7342 * is being translated.
7343 *
7344 * Note: Because Linux currently doesn't page the kernel and all
7345 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7346 */
7347ADV_PADDR
7348DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007349 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007350{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007351 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007353 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007354
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007355 ASC_DBG4(4,
7356 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7357 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7358 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007359
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007360 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007361}
7362
7363/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007364 * --- Tracing and Debugging Functions
7365 */
7366
7367#ifdef ADVANSYS_STATS
7368#ifdef CONFIG_PROC_FS
7369/*
7370 * asc_prt_board_stats()
7371 *
7372 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7373 * cf. asc_prt_line().
7374 *
7375 * Return the number of characters copied into 'cp'. No more than
7376 * 'cplen' characters will be copied to 'cp'.
7377 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007378static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007379{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007380 int leftlen;
7381 int totlen;
7382 int len;
7383 struct asc_stats *s;
7384 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007385
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007386 leftlen = cplen;
7387 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007389 boardp = ASC_BOARDP(shost);
7390 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007391
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007392 len = asc_prt_line(cp, leftlen,
7393 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7394 shost->host_no);
7395 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007396
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007397 len = asc_prt_line(cp, leftlen,
7398 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7399 s->queuecommand, s->reset, s->biosparam,
7400 s->interrupt);
7401 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007403 len = asc_prt_line(cp, leftlen,
7404 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7405 s->callback, s->done, s->build_error,
7406 s->adv_build_noreq, s->adv_build_nosg);
7407 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007408
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007409 len = asc_prt_line(cp, leftlen,
7410 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7411 s->exe_noerror, s->exe_busy, s->exe_error,
7412 s->exe_unknown);
7413 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007414
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007415 /*
7416 * Display data transfer statistics.
7417 */
7418 if (s->cont_cnt > 0) {
7419 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7420 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007421
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007422 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7423 s->cont_xfer / 2,
7424 ASC_TENTHS(s->cont_xfer, 2));
7425 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007426
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007427 /* Contiguous transfer average size */
7428 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7429 (s->cont_xfer / 2) / s->cont_cnt,
7430 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7431 ASC_PRT_NEXT();
7432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007433
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007434 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007436 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7437 s->sg_cnt, s->sg_elem);
7438 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007439
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007440 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7441 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7442 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007443
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007444 /* Scatter gather transfer statistics */
7445 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7446 s->sg_elem / s->sg_cnt,
7447 ASC_TENTHS(s->sg_elem, s->sg_cnt));
7448 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007450 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
7451 (s->sg_xfer / 2) / s->sg_elem,
7452 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7453 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007454
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007455 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7456 (s->sg_xfer / 2) / s->sg_cnt,
7457 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7458 ASC_PRT_NEXT();
7459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007460
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007461 /*
7462 * Display request queuing statistics.
7463 */
7464 len = asc_prt_line(cp, leftlen,
7465 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7466 HZ);
7467 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007468
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007469 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007470}
7471
7472/*
7473 * asc_prt_target_stats()
7474 *
7475 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7476 * cf. asc_prt_line().
7477 *
7478 * This is separated from asc_prt_board_stats because a full set
7479 * of targets will overflow ASC_PRTBUF_SIZE.
7480 *
7481 * Return the number of characters copied into 'cp'. No more than
7482 * 'cplen' characters will be copied to 'cp'.
7483 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007484static int
7485asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007486{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007487 int leftlen;
7488 int totlen;
7489 int len;
7490 struct asc_stats *s;
7491 ushort chip_scsi_id;
7492 asc_board_t *boardp;
7493 asc_queue_t *active;
7494 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007495
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007496 leftlen = cplen;
7497 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007498
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007499 boardp = ASC_BOARDP(shost);
7500 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007501
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007502 active = &ASC_BOARDP(shost)->active;
7503 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007504
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007505 if (ASC_NARROW_BOARD(boardp)) {
7506 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7507 } else {
7508 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007510
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007511 if ((chip_scsi_id == tgt_id) ||
7512 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7513 return 0;
7514 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007515
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007516 do {
7517 if (active->q_tot_cnt[tgt_id] > 0
7518 || waiting->q_tot_cnt[tgt_id] > 0) {
7519 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
7520 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007521
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007522 len = asc_prt_line(cp, leftlen,
7523 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7524 active->q_cur_cnt[tgt_id],
7525 active->q_max_cnt[tgt_id],
7526 active->q_tot_cnt[tgt_id],
7527 active->q_min_tim[tgt_id],
7528 active->q_max_tim[tgt_id],
7529 (active->q_tot_cnt[tgt_id] ==
7530 0) ? 0 : (active->
7531 q_tot_tim[tgt_id] /
7532 active->
7533 q_tot_cnt[tgt_id]),
7534 (active->q_tot_cnt[tgt_id] ==
7535 0) ? 0 : ASC_TENTHS(active->
7536 q_tot_tim
7537 [tgt_id],
7538 active->
7539 q_tot_cnt
7540 [tgt_id]));
7541 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007542
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007543 len = asc_prt_line(cp, leftlen,
7544 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7545 waiting->q_cur_cnt[tgt_id],
7546 waiting->q_max_cnt[tgt_id],
7547 waiting->q_tot_cnt[tgt_id],
7548 waiting->q_min_tim[tgt_id],
7549 waiting->q_max_tim[tgt_id],
7550 (waiting->q_tot_cnt[tgt_id] ==
7551 0) ? 0 : (waiting->
7552 q_tot_tim[tgt_id] /
7553 waiting->
7554 q_tot_cnt[tgt_id]),
7555 (waiting->q_tot_cnt[tgt_id] ==
7556 0) ? 0 : ASC_TENTHS(waiting->
7557 q_tot_tim
7558 [tgt_id],
7559 waiting->
7560 q_tot_cnt
7561 [tgt_id]));
7562 ASC_PRT_NEXT();
7563 }
7564 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007565
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007566 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007567}
7568#endif /* CONFIG_PROC_FS */
7569#endif /* ADVANSYS_STATS */
7570
7571#ifdef ADVANSYS_DEBUG
7572/*
7573 * asc_prt_scsi_host()
7574 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007575static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007576{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007577 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007578
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007579 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007580
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007581 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7582 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7583 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007584
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04007585 printk(" base 0x%lx, io_port 0x%lx, irq 0x%x,\n",
7586 (ulong)s->base, (ulong)s->io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007587
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007588 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7589 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007590
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007591 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7592 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007593
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007594 if (ASC_NARROW_BOARD(boardp)) {
7595 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7596 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7597 } else {
7598 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7599 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7600 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007601}
7602
7603/*
7604 * asc_prt_scsi_cmnd()
7605 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007606static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007607{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007608 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007609
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007610 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7611 (ulong)s->device->host, (ulong)s->device, s->device->id,
7612 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007613
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007614 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007615
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007616 printk("sc_data_direction %u, resid %d\n",
7617 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007618
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007619 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007620
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007621 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7622 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007623
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007624 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007625
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007626 printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
7627 s->scsi_done, s->done, s->host_scribble, s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007628
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007629 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007630}
7631
7632/*
7633 * asc_prt_asc_dvc_var()
7634 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007635static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007636{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007637 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007638
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007639 printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
7640 "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007641
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007642 printk(" bus_type %d, isr_callback 0x%p, exe_callback 0x%p, "
7643 "init_sdtr 0x%x,\n", h->bus_type, h->isr_callback,
7644 h->exe_callback, (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007645
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007646 printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
7647 "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
7648 (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
7649 (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007650
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007651 printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
7652 "%u,\n", (unsigned)h->queue_full_or_busy,
7653 (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007654
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007655 printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
7656 "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
7657 (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
7658 (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007659
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007660 printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
7661 "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
7662 (unsigned)h->init_state, (unsigned)h->no_scam,
7663 (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007664
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007665 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007666}
7667
7668/*
7669 * asc_prt_asc_dvc_cfg()
7670 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007671static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007672{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007673 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007675 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7676 h->can_tagged_qng, h->cmd_qng_enabled);
7677 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7678 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007679
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007680 printk
7681 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7682 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7683 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007684
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007685 printk
7686 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7687 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7688 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007689
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007690 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7691 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007692}
7693
7694/*
7695 * asc_prt_asc_scsi_q()
7696 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007697static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007698{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007699 ASC_SG_HEAD *sgp;
7700 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007701
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007702 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007703
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007704 printk
7705 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7706 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7707 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007708
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007709 printk
7710 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7711 (ulong)le32_to_cpu(q->q1.data_addr),
7712 (ulong)le32_to_cpu(q->q1.data_cnt),
7713 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007714
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007715 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
7716 (ulong)q->cdbptr, q->q2.cdb_len,
7717 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007718
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007719 if (q->sg_head) {
7720 sgp = q->sg_head;
7721 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
7722 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
7723 sgp->queue_cnt);
7724 for (i = 0; i < sgp->entry_cnt; i++) {
7725 printk(" [%u]: addr 0x%lx, bytes %lu\n",
7726 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
7727 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
7728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007729
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731}
7732
7733/*
7734 * asc_prt_asc_qdone_info()
7735 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007736static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007737{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007738 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
7739 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
7740 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
7741 q->d2.tag_code);
7742 printk
7743 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
7744 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007745}
7746
7747/*
7748 * asc_prt_adv_dvc_var()
7749 *
7750 * Display an ADV_DVC_VAR structure.
7751 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007752static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007753{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007754 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007755
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007756 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
7757 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007758
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007759 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
7760 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
7761 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007763 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
7764 (unsigned)h->start_motor,
7765 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007766
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007767 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
7768 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
7769 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007771 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
7772 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007773
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007774 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
7775 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007776
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007777 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
7778 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007779}
7780
7781/*
7782 * asc_prt_adv_dvc_cfg()
7783 *
7784 * Display an ADV_DVC_CFG structure.
7785 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007786static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007787{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007788 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007790 printk(" disc_enable 0x%x, termination 0x%x\n",
7791 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007792
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007793 printk(" chip_version 0x%x, mcode_date 0x%x\n",
7794 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007796 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
7797 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007798
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007799 printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
7800 h->control_flag, h->pci_slot_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007801}
7802
7803/*
7804 * asc_prt_adv_scsi_req_q()
7805 *
7806 * Display an ADV_SCSI_REQ_Q structure.
7807 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007808static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007809{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007810 int sg_blk_cnt;
7811 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007812
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007813 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007814
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007815 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
7816 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007817
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007818 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
7819 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007820
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007821 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7822 (ulong)le32_to_cpu(q->data_cnt),
7823 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007824
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007825 printk
7826 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
7827 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007829 printk(" sg_working_ix 0x%x, target_cmd %u\n",
7830 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007832 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
7833 (ulong)le32_to_cpu(q->scsiq_rptr),
7834 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007835
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007836 /* Display the request's ADV_SG_BLOCK structures. */
7837 if (q->sg_list_ptr != NULL) {
7838 sg_blk_cnt = 0;
7839 while (1) {
7840 /*
7841 * 'sg_ptr' is a physical address. Convert it to a virtual
7842 * address by indexing 'sg_blk_cnt' into the virtual address
7843 * array 'sg_list_ptr'.
7844 *
7845 * XXX - Assumes all SG physical blocks are virtually contiguous.
7846 */
7847 sg_ptr =
7848 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
7849 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
7850 if (sg_ptr->sg_ptr == 0) {
7851 break;
7852 }
7853 sg_blk_cnt++;
7854 }
7855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007856}
7857
7858/*
7859 * asc_prt_adv_sgblock()
7860 *
7861 * Display an ADV_SG_BLOCK structure.
7862 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007863static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007864{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007865 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007866
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007867 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
7868 (ulong)b, sgblockno);
7869 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
7870 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
7871 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
7872 if (b->sg_ptr != 0) {
7873 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
7874 }
7875 for (i = 0; i < b->sg_cnt; i++) {
7876 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
7877 i, (ulong)b->sg_list[i].sg_addr,
7878 (ulong)b->sg_list[i].sg_count);
7879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007880}
7881
7882/*
7883 * asc_prt_hex()
7884 *
7885 * Print hexadecimal output in 4 byte groupings 32 bytes
7886 * or 8 double-words per line.
7887 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007888static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007889{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007890 int i;
7891 int j;
7892 int k;
7893 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007894
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007895 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007896
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007897 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007898
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007899 /* Display a maximum of 8 double-words per line. */
7900 if ((k = (l - i) / 4) >= 8) {
7901 k = 8;
7902 m = 0;
7903 } else {
7904 m = (l - i) % 4;
7905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007906
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007907 for (j = 0; j < k; j++) {
7908 printk(" %2.2X%2.2X%2.2X%2.2X",
7909 (unsigned)s[i + (j * 4)],
7910 (unsigned)s[i + (j * 4) + 1],
7911 (unsigned)s[i + (j * 4) + 2],
7912 (unsigned)s[i + (j * 4) + 3]);
7913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007914
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007915 switch (m) {
7916 case 0:
7917 default:
7918 break;
7919 case 1:
7920 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
7921 break;
7922 case 2:
7923 printk(" %2.2X%2.2X",
7924 (unsigned)s[i + (j * 4)],
7925 (unsigned)s[i + (j * 4) + 1]);
7926 break;
7927 case 3:
7928 printk(" %2.2X%2.2X%2.2X",
7929 (unsigned)s[i + (j * 4) + 1],
7930 (unsigned)s[i + (j * 4) + 2],
7931 (unsigned)s[i + (j * 4) + 3]);
7932 break;
7933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007934
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007935 printk("\n");
7936 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007937}
7938#endif /* ADVANSYS_DEBUG */
7939
7940/*
7941 * --- Asc Library Functions
7942 */
7943
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007944static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007945{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007946 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007948 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7949 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
7950 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007951}
7952
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007953static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007954{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007955 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007956
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007957 if (AscGetChipScsiID(iop_base) == new_host_id) {
7958 return (new_host_id);
7959 }
7960 cfg_lsw = AscGetChipCfgLsw(iop_base);
7961 cfg_lsw &= 0xF8FF;
7962 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
7963 AscSetChipCfgLsw(iop_base, cfg_lsw);
7964 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007965}
7966
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007967static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007968{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007969 unsigned char sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007970
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007971 AscSetBank(iop_base, 1);
7972 sc = inp(iop_base + IOP_REG_SC);
7973 AscSetBank(iop_base, 0);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007974 return sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007975}
7976
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007977static unsigned char __devinit
7978AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007979{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007980 if (bus_type & ASC_IS_EISA) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007981 PortAddr eisa_iop;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007982 unsigned char revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007983 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7984 (PortAddr) ASC_EISA_REV_IOP_MASK;
7985 revision = inp(eisa_iop);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007986 return ASC_CHIP_MIN_VER_EISA - 1 + revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007987 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007988 return AscGetChipVerNo(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007989}
7990
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007991static ASC_DCNT
7992AscLoadMicroCode(PortAddr iop_base,
7993 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007994{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007995 ASC_DCNT chksum;
7996 ushort mcode_word_size;
7997 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007998
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007999 /* Write the microcode buffer starting at LRAM address 0. */
8000 mcode_word_size = (ushort)(mcode_size >> 1);
8001 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
8002 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008004 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
8005 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
8006 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
8007 (ushort)ASC_CODE_SEC_BEG,
8008 (ushort)((mcode_size -
8009 s_addr - (ushort)
8010 ASC_CODE_SEC_BEG) /
8011 2));
8012 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
8013 (ulong)mcode_chksum);
8014 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
8015 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
8016 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008017}
8018
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008019static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008020{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008021 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008022
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008023 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
8024 iop_base, AscGetChipSignatureByte(iop_base));
8025 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
8026 ASC_DBG2(1,
8027 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
8028 iop_base, AscGetChipSignatureWord(iop_base));
8029 sig_word = AscGetChipSignatureWord(iop_base);
8030 if ((sig_word == (ushort)ASC_1000_ID0W) ||
8031 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
8032 return (1);
8033 }
8034 }
8035 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008036}
8037
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008038static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008039{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008040 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
8041 AscSetChipStatus(iop_base, 0);
8042 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008043}
8044
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008045static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008046{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008047 ushort cfg_lsw;
8048 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008049
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008050 if ((bus_type & ASC_IS_EISA) != 0) {
8051 cfg_lsw = AscGetEisaChipCfg(iop_base);
8052 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8053 if ((chip_irq == 13) || (chip_irq > 15)) {
8054 return (0);
8055 }
8056 return (chip_irq);
8057 }
8058 if ((bus_type & ASC_IS_VL) != 0) {
8059 cfg_lsw = AscGetChipCfgLsw(iop_base);
8060 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8061 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8062 return (0);
8063 }
8064 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8065 }
8066 cfg_lsw = AscGetChipCfgLsw(iop_base);
8067 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8068 if (chip_irq == 3)
8069 chip_irq += (uchar)2;
8070 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008071}
8072
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008073static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008074AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008075{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008076 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008077
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008078 if ((bus_type & ASC_IS_VL) != 0) {
8079 if (irq_no != 0) {
8080 if ((irq_no < ASC_MIN_IRQ_NO)
8081 || (irq_no > ASC_MAX_IRQ_NO)) {
8082 irq_no = 0;
8083 } else {
8084 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8085 }
8086 }
8087 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8088 cfg_lsw |= (ushort)0x0010;
8089 AscSetChipCfgLsw(iop_base, cfg_lsw);
8090 AscToggleIRQAct(iop_base);
8091 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8092 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8093 AscSetChipCfgLsw(iop_base, cfg_lsw);
8094 AscToggleIRQAct(iop_base);
8095 return (AscGetChipIRQ(iop_base, bus_type));
8096 }
8097 if ((bus_type & (ASC_IS_ISA)) != 0) {
8098 if (irq_no == 15)
8099 irq_no -= (uchar)2;
8100 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8101 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8102 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8103 AscSetChipCfgLsw(iop_base, cfg_lsw);
8104 return (AscGetChipIRQ(iop_base, bus_type));
8105 }
8106 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008107}
8108
8109#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008110static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008111{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008112 if (dma_channel < 4) {
8113 outp(0x000B, (ushort)(0xC0 | dma_channel));
8114 outp(0x000A, dma_channel);
8115 } else if (dma_channel < 8) {
8116 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8117 outp(0x00D4, (ushort)(dma_channel - 4));
8118 }
8119 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008120}
8121#endif /* CONFIG_ISA */
8122
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008123static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008124{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008125 EXT_MSG ext_msg;
8126 EXT_MSG out_msg;
8127 ushort halt_q_addr;
8128 int sdtr_accept;
8129 ushort int_halt_code;
8130 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8131 ASC_SCSI_BIT_ID_TYPE target_id;
8132 PortAddr iop_base;
8133 uchar tag_code;
8134 uchar q_status;
8135 uchar halt_qp;
8136 uchar sdtr_data;
8137 uchar target_ix;
8138 uchar q_cntl, tid_no;
8139 uchar cur_dvc_qng;
8140 uchar asyn_sdtr;
8141 uchar scsi_status;
8142 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008143
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008144 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8145 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008146
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008147 iop_base = asc_dvc->iop_base;
8148 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008149
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008150 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8151 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8152 target_ix = AscReadLramByte(iop_base,
8153 (ushort)(halt_q_addr +
8154 (ushort)ASC_SCSIQ_B_TARGET_IX));
8155 q_cntl =
8156 AscReadLramByte(iop_base,
8157 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8158 tid_no = ASC_TIX_TO_TID(target_ix);
8159 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8160 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8161 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8162 } else {
8163 asyn_sdtr = 0;
8164 }
8165 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8166 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8167 AscSetChipSDTR(iop_base, 0, tid_no);
8168 boardp->sdtr_data[tid_no] = 0;
8169 }
8170 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8171 return (0);
8172 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8173 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8174 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8175 boardp->sdtr_data[tid_no] = asyn_sdtr;
8176 }
8177 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8178 return (0);
8179 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008180
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008181 AscMemWordCopyPtrFromLram(iop_base,
8182 ASCV_MSGIN_BEG,
8183 (uchar *)&ext_msg,
8184 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008185
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008186 if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8187 ext_msg.msg_req == EXTENDED_SDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008188 ext_msg.msg_len == MS_SDTR_LEN) {
8189 sdtr_accept = TRUE;
8190 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008192 sdtr_accept = FALSE;
8193 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8194 }
8195 if ((ext_msg.xfer_period <
8196 asc_dvc->sdtr_period_tbl[asc_dvc->
8197 host_init_sdtr_index])
8198 || (ext_msg.xfer_period >
8199 asc_dvc->sdtr_period_tbl[asc_dvc->
8200 max_sdtr_index])) {
8201 sdtr_accept = FALSE;
8202 ext_msg.xfer_period =
8203 asc_dvc->sdtr_period_tbl[asc_dvc->
8204 host_init_sdtr_index];
8205 }
8206 if (sdtr_accept) {
8207 sdtr_data =
8208 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8209 ext_msg.req_ack_offset);
8210 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008212 q_cntl |= QC_MSG_OUT;
8213 asc_dvc->init_sdtr &= ~target_id;
8214 asc_dvc->sdtr_done &= ~target_id;
8215 AscSetChipSDTR(iop_base, asyn_sdtr,
8216 tid_no);
8217 boardp->sdtr_data[tid_no] = asyn_sdtr;
8218 }
8219 }
8220 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008221
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008222 q_cntl &= ~QC_MSG_OUT;
8223 asc_dvc->init_sdtr &= ~target_id;
8224 asc_dvc->sdtr_done &= ~target_id;
8225 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8226 } else {
8227 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008228
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008229 q_cntl &= ~QC_MSG_OUT;
8230 asc_dvc->sdtr_done |= target_id;
8231 asc_dvc->init_sdtr |= target_id;
8232 asc_dvc->pci_fix_asyn_xfer &=
8233 ~target_id;
8234 sdtr_data =
8235 AscCalSDTRData(asc_dvc,
8236 ext_msg.xfer_period,
8237 ext_msg.
8238 req_ack_offset);
8239 AscSetChipSDTR(iop_base, sdtr_data,
8240 tid_no);
8241 boardp->sdtr_data[tid_no] = sdtr_data;
8242 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008243
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008244 q_cntl |= QC_MSG_OUT;
8245 AscMsgOutSDTR(asc_dvc,
8246 ext_msg.xfer_period,
8247 ext_msg.req_ack_offset);
8248 asc_dvc->pci_fix_asyn_xfer &=
8249 ~target_id;
8250 sdtr_data =
8251 AscCalSDTRData(asc_dvc,
8252 ext_msg.xfer_period,
8253 ext_msg.
8254 req_ack_offset);
8255 AscSetChipSDTR(iop_base, sdtr_data,
8256 tid_no);
8257 boardp->sdtr_data[tid_no] = sdtr_data;
8258 asc_dvc->sdtr_done |= target_id;
8259 asc_dvc->init_sdtr |= target_id;
8260 }
8261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008262
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008263 AscWriteLramByte(iop_base,
8264 (ushort)(halt_q_addr +
8265 (ushort)ASC_SCSIQ_B_CNTL),
8266 q_cntl);
8267 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8268 return (0);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008269 } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8270 ext_msg.msg_req == EXTENDED_WDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008271 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008273 ext_msg.wdtr_width = 0;
8274 AscMemWordCopyPtrToLram(iop_base,
8275 ASCV_MSGOUT_BEG,
8276 (uchar *)&ext_msg,
8277 sizeof(EXT_MSG) >> 1);
8278 q_cntl |= QC_MSG_OUT;
8279 AscWriteLramByte(iop_base,
8280 (ushort)(halt_q_addr +
8281 (ushort)ASC_SCSIQ_B_CNTL),
8282 q_cntl);
8283 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8284 return (0);
8285 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008286
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008287 ext_msg.msg_type = MESSAGE_REJECT;
8288 AscMemWordCopyPtrToLram(iop_base,
8289 ASCV_MSGOUT_BEG,
8290 (uchar *)&ext_msg,
8291 sizeof(EXT_MSG) >> 1);
8292 q_cntl |= QC_MSG_OUT;
8293 AscWriteLramByte(iop_base,
8294 (ushort)(halt_q_addr +
8295 (ushort)ASC_SCSIQ_B_CNTL),
8296 q_cntl);
8297 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8298 return (0);
8299 }
8300 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008301
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008302 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008303
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008304 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008305
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008306 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008308 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8309 q_cntl |= QC_MSG_OUT;
8310 AscMsgOutSDTR(asc_dvc,
8311 asc_dvc->
8312 sdtr_period_tbl[(sdtr_data >> 4) &
8313 (uchar)(asc_dvc->
8314 max_sdtr_index -
8315 1)],
8316 (uchar)(sdtr_data & (uchar)
8317 ASC_SYN_MAX_OFFSET));
8318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008320 AscWriteLramByte(iop_base,
8321 (ushort)(halt_q_addr +
8322 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008323
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008324 tag_code = AscReadLramByte(iop_base,
8325 (ushort)(halt_q_addr + (ushort)
8326 ASC_SCSIQ_B_TAG_CODE));
8327 tag_code &= 0xDC;
8328 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8329 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8330 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008331
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008332 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8333 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008335 }
8336 AscWriteLramByte(iop_base,
8337 (ushort)(halt_q_addr +
8338 (ushort)ASC_SCSIQ_B_TAG_CODE),
8339 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008340
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008341 q_status = AscReadLramByte(iop_base,
8342 (ushort)(halt_q_addr + (ushort)
8343 ASC_SCSIQ_B_STATUS));
8344 q_status |= (QS_READY | QS_BUSY);
8345 AscWriteLramByte(iop_base,
8346 (ushort)(halt_q_addr +
8347 (ushort)ASC_SCSIQ_B_STATUS),
8348 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008349
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008350 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8351 scsi_busy &= ~target_id;
8352 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008353
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008354 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8355 return (0);
8356 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008357
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008358 AscMemWordCopyPtrFromLram(iop_base,
8359 ASCV_MSGOUT_BEG,
8360 (uchar *)&out_msg,
8361 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008362
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008363 if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008364 (out_msg.msg_len == MS_SDTR_LEN) &&
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008365 (out_msg.msg_req == EXTENDED_SDTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008366
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008367 asc_dvc->init_sdtr &= ~target_id;
8368 asc_dvc->sdtr_done &= ~target_id;
8369 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8370 boardp->sdtr_data[tid_no] = asyn_sdtr;
8371 }
8372 q_cntl &= ~QC_MSG_OUT;
8373 AscWriteLramByte(iop_base,
8374 (ushort)(halt_q_addr +
8375 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8376 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8377 return (0);
8378 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008379
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008380 scsi_status = AscReadLramByte(iop_base,
8381 (ushort)((ushort)halt_q_addr +
8382 (ushort)
8383 ASC_SCSIQ_SCSI_STATUS));
8384 cur_dvc_qng =
8385 AscReadLramByte(iop_base,
8386 (ushort)((ushort)ASC_QADR_BEG +
8387 (ushort)target_ix));
8388 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008389
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008390 scsi_busy = AscReadLramByte(iop_base,
8391 (ushort)ASCV_SCSIBUSY_B);
8392 scsi_busy |= target_id;
8393 AscWriteLramByte(iop_base,
8394 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8395 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008396
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008397 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8398 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8399 cur_dvc_qng -= 1;
8400 asc_dvc->max_dvc_qng[tid_no] =
8401 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008403 AscWriteLramByte(iop_base,
8404 (ushort)((ushort)
8405 ASCV_MAX_DVC_QNG_BEG
8406 + (ushort)
8407 tid_no),
8408 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008410 /*
8411 * Set the device queue depth to the number of
8412 * active requests when the QUEUE FULL condition
8413 * was encountered.
8414 */
8415 boardp->queue_full |= target_id;
8416 boardp->queue_full_cnt[tid_no] =
8417 cur_dvc_qng;
8418 }
8419 }
8420 }
8421 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8422 return (0);
8423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008424#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008425 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8426 uchar q_no;
8427 ushort q_addr;
8428 uchar sg_wk_q_no;
8429 uchar first_sg_wk_q_no;
8430 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8431 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8432 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8433 ushort sg_list_dwords;
8434 ushort sg_entry_cnt;
8435 uchar next_qp;
8436 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008437
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008438 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8439 if (q_no == ASC_QLINK_END) {
8440 return (0);
8441 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008443 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008444
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008445 /*
8446 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8447 * structure pointer using a macro provided by the driver.
8448 * The ASC_SCSI_REQ pointer provides a pointer to the
8449 * host ASC_SG_HEAD structure.
8450 */
8451 /* Read request's SRB pointer. */
8452 scsiq = (ASC_SCSI_Q *)
8453 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8454 (ushort)
8455 (q_addr +
8456 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008457
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008458 /*
8459 * Get request's first and working SG queue.
8460 */
8461 sg_wk_q_no = AscReadLramByte(iop_base,
8462 (ushort)(q_addr +
8463 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008464
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008465 first_sg_wk_q_no = AscReadLramByte(iop_base,
8466 (ushort)(q_addr +
8467 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008468
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008469 /*
8470 * Reset request's working SG queue back to the
8471 * first SG queue.
8472 */
8473 AscWriteLramByte(iop_base,
8474 (ushort)(q_addr +
8475 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8476 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008477
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008478 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008479
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008480 /*
8481 * Set sg_entry_cnt to the number of SG elements
8482 * that will be completed on this interrupt.
8483 *
8484 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8485 * SG elements. The data_cnt and data_addr fields which
8486 * add 1 to the SG element capacity are not used when
8487 * restarting SG handling after a halt.
8488 */
8489 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8490 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008491
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008492 /*
8493 * Keep track of remaining number of SG elements that will
8494 * need to be handled on the next interrupt.
8495 */
8496 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8497 } else {
8498 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8499 scsiq->remain_sg_entry_cnt = 0;
8500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008501
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008502 /*
8503 * Copy SG elements into the list of allocated SG queues.
8504 *
8505 * Last index completed is saved in scsiq->next_sg_index.
8506 */
8507 next_qp = first_sg_wk_q_no;
8508 q_addr = ASC_QNO_TO_QADDR(next_qp);
8509 scsi_sg_q.sg_head_qp = q_no;
8510 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8511 for (i = 0; i < sg_head->queue_cnt; i++) {
8512 scsi_sg_q.seq_no = i + 1;
8513 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8514 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8515 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8516 /*
8517 * After very first SG queue RISC FW uses next
8518 * SG queue first element then checks sg_list_cnt
8519 * against zero and then decrements, so set
8520 * sg_list_cnt 1 less than number of SG elements
8521 * in each SG queue.
8522 */
8523 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8524 scsi_sg_q.sg_cur_list_cnt =
8525 ASC_SG_LIST_PER_Q - 1;
8526 } else {
8527 /*
8528 * This is the last SG queue in the list of
8529 * allocated SG queues. If there are more
8530 * SG elements than will fit in the allocated
8531 * queues, then set the QCSG_SG_XFER_MORE flag.
8532 */
8533 if (scsiq->remain_sg_entry_cnt != 0) {
8534 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8535 } else {
8536 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8537 }
8538 /* equals sg_entry_cnt * 2 */
8539 sg_list_dwords = sg_entry_cnt << 1;
8540 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8541 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8542 sg_entry_cnt = 0;
8543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008544
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008545 scsi_sg_q.q_no = next_qp;
8546 AscMemWordCopyPtrToLram(iop_base,
8547 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8548 (uchar *)&scsi_sg_q,
8549 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008550
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008551 AscMemDWordCopyPtrToLram(iop_base,
8552 q_addr + ASC_SGQ_LIST_BEG,
8553 (uchar *)&sg_head->
8554 sg_list[scsiq->next_sg_index],
8555 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008556
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008557 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008558
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008559 /*
8560 * If the just completed SG queue contained the
8561 * last SG element, then no more SG queues need
8562 * to be written.
8563 */
8564 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8565 break;
8566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008567
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008568 next_qp = AscReadLramByte(iop_base,
8569 (ushort)(q_addr +
8570 ASC_SCSIQ_B_FWD));
8571 q_addr = ASC_QNO_TO_QADDR(next_qp);
8572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008573
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008574 /*
8575 * Clear the halt condition so the RISC will be restarted
8576 * after the return.
8577 */
8578 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8579 return (0);
8580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008581#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008582 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008583}
8584
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008585static uchar
8586_AscCopyLramScsiDoneQ(PortAddr iop_base,
8587 ushort q_addr,
8588 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008589{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008590 ushort _val;
8591 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008592
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008593 DvcGetQinfo(iop_base,
8594 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8595 (uchar *)scsiq,
8596 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008597
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008598 _val = AscReadLramWord(iop_base,
8599 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8600 scsiq->q_status = (uchar)_val;
8601 scsiq->q_no = (uchar)(_val >> 8);
8602 _val = AscReadLramWord(iop_base,
8603 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8604 scsiq->cntl = (uchar)_val;
8605 sg_queue_cnt = (uchar)(_val >> 8);
8606 _val = AscReadLramWord(iop_base,
8607 (ushort)(q_addr +
8608 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8609 scsiq->sense_len = (uchar)_val;
8610 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008611
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008612 /*
8613 * Read high word of remain bytes from alternate location.
8614 */
8615 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
8616 (ushort)(q_addr +
8617 (ushort)
8618 ASC_SCSIQ_W_ALT_DC1)))
8619 << 16);
8620 /*
8621 * Read low word of remain bytes from original location.
8622 */
8623 scsiq->remain_bytes += AscReadLramWord(iop_base,
8624 (ushort)(q_addr + (ushort)
8625 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008627 scsiq->remain_bytes &= max_dma_count;
8628 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008629}
8630
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008631static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008632{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008633 uchar next_qp;
8634 uchar n_q_used;
8635 uchar sg_list_qp;
8636 uchar sg_queue_cnt;
8637 uchar q_cnt;
8638 uchar done_q_tail;
8639 uchar tid_no;
8640 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8641 ASC_SCSI_BIT_ID_TYPE target_id;
8642 PortAddr iop_base;
8643 ushort q_addr;
8644 ushort sg_q_addr;
8645 uchar cur_target_qng;
8646 ASC_QDONE_INFO scsiq_buf;
8647 ASC_QDONE_INFO *scsiq;
8648 int false_overrun;
8649 ASC_ISR_CALLBACK asc_isr_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008650
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008651 iop_base = asc_dvc->iop_base;
8652 asc_isr_callback = asc_dvc->isr_callback;
8653 n_q_used = 1;
8654 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
8655 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
8656 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
8657 next_qp = AscReadLramByte(iop_base,
8658 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
8659 if (next_qp != ASC_QLINK_END) {
8660 AscPutVarDoneQTail(iop_base, next_qp);
8661 q_addr = ASC_QNO_TO_QADDR(next_qp);
8662 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
8663 asc_dvc->max_dma_count);
8664 AscWriteLramByte(iop_base,
8665 (ushort)(q_addr +
8666 (ushort)ASC_SCSIQ_B_STATUS),
8667 (uchar)(scsiq->
8668 q_status & (uchar)~(QS_READY |
8669 QS_ABORTED)));
8670 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
8671 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
8672 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
8673 sg_q_addr = q_addr;
8674 sg_list_qp = next_qp;
8675 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
8676 sg_list_qp = AscReadLramByte(iop_base,
8677 (ushort)(sg_q_addr
8678 + (ushort)
8679 ASC_SCSIQ_B_FWD));
8680 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
8681 if (sg_list_qp == ASC_QLINK_END) {
8682 AscSetLibErrorCode(asc_dvc,
8683 ASCQ_ERR_SG_Q_LINKS);
8684 scsiq->d3.done_stat = QD_WITH_ERROR;
8685 scsiq->d3.host_stat =
8686 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
8687 goto FATAL_ERR_QDONE;
8688 }
8689 AscWriteLramByte(iop_base,
8690 (ushort)(sg_q_addr + (ushort)
8691 ASC_SCSIQ_B_STATUS),
8692 QS_FREE);
8693 }
8694 n_q_used = sg_queue_cnt + 1;
8695 AscPutVarDoneQTail(iop_base, sg_list_qp);
8696 }
8697 if (asc_dvc->queue_full_or_busy & target_id) {
8698 cur_target_qng = AscReadLramByte(iop_base,
8699 (ushort)((ushort)
8700 ASC_QADR_BEG
8701 + (ushort)
8702 scsiq->d2.
8703 target_ix));
8704 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
8705 scsi_busy = AscReadLramByte(iop_base, (ushort)
8706 ASCV_SCSIBUSY_B);
8707 scsi_busy &= ~target_id;
8708 AscWriteLramByte(iop_base,
8709 (ushort)ASCV_SCSIBUSY_B,
8710 scsi_busy);
8711 asc_dvc->queue_full_or_busy &= ~target_id;
8712 }
8713 }
8714 if (asc_dvc->cur_total_qng >= n_q_used) {
8715 asc_dvc->cur_total_qng -= n_q_used;
8716 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
8717 asc_dvc->cur_dvc_qng[tid_no]--;
8718 }
8719 } else {
8720 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
8721 scsiq->d3.done_stat = QD_WITH_ERROR;
8722 goto FATAL_ERR_QDONE;
8723 }
8724 if ((scsiq->d2.srb_ptr == 0UL) ||
8725 ((scsiq->q_status & QS_ABORTED) != 0)) {
8726 return (0x11);
8727 } else if (scsiq->q_status == QS_DONE) {
8728 false_overrun = FALSE;
8729 if (scsiq->extra_bytes != 0) {
8730 scsiq->remain_bytes +=
8731 (ADV_DCNT)scsiq->extra_bytes;
8732 }
8733 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
8734 if (scsiq->d3.host_stat ==
8735 QHSTA_M_DATA_OVER_RUN) {
8736 if ((scsiq->
8737 cntl & (QC_DATA_IN | QC_DATA_OUT))
8738 == 0) {
8739 scsiq->d3.done_stat =
8740 QD_NO_ERROR;
8741 scsiq->d3.host_stat =
8742 QHSTA_NO_ERROR;
8743 } else if (false_overrun) {
8744 scsiq->d3.done_stat =
8745 QD_NO_ERROR;
8746 scsiq->d3.host_stat =
8747 QHSTA_NO_ERROR;
8748 }
8749 } else if (scsiq->d3.host_stat ==
8750 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
8751 AscStopChip(iop_base);
8752 AscSetChipControl(iop_base,
8753 (uchar)(CC_SCSI_RESET
8754 | CC_HALT));
8755 DvcDelayNanoSecond(asc_dvc, 60000);
8756 AscSetChipControl(iop_base, CC_HALT);
8757 AscSetChipStatus(iop_base,
8758 CIW_CLR_SCSI_RESET_INT);
8759 AscSetChipStatus(iop_base, 0);
8760 AscSetChipControl(iop_base, 0);
8761 }
8762 }
8763 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8764 (*asc_isr_callback) (asc_dvc, scsiq);
8765 } else {
8766 if ((AscReadLramByte(iop_base,
8767 (ushort)(q_addr + (ushort)
8768 ASC_SCSIQ_CDB_BEG))
8769 == START_STOP)) {
8770 asc_dvc->unit_not_ready &= ~target_id;
8771 if (scsiq->d3.done_stat != QD_NO_ERROR) {
8772 asc_dvc->start_motor &=
8773 ~target_id;
8774 }
8775 }
8776 }
8777 return (1);
8778 } else {
8779 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
8780 FATAL_ERR_QDONE:
8781 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8782 (*asc_isr_callback) (asc_dvc, scsiq);
8783 }
8784 return (0x80);
8785 }
8786 }
8787 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008788}
8789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008790static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008791{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008792 ASC_CS_TYPE chipstat;
8793 PortAddr iop_base;
8794 ushort saved_ram_addr;
8795 uchar ctrl_reg;
8796 uchar saved_ctrl_reg;
8797 int int_pending;
8798 int status;
8799 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008801 iop_base = asc_dvc->iop_base;
8802 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008803
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008804 if (AscIsIntPending(iop_base) == 0) {
8805 return int_pending;
8806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008807
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008808 if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
8809 || (asc_dvc->isr_callback == 0)
8810 ) {
8811 return (ERR);
8812 }
8813 if (asc_dvc->in_critical_cnt != 0) {
8814 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
8815 return (ERR);
8816 }
8817 if (asc_dvc->is_in_int) {
8818 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
8819 return (ERR);
8820 }
8821 asc_dvc->is_in_int = TRUE;
8822 ctrl_reg = AscGetChipControl(iop_base);
8823 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
8824 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
8825 chipstat = AscGetChipStatus(iop_base);
8826 if (chipstat & CSW_SCSI_RESET_LATCH) {
8827 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
8828 int i = 10;
8829 int_pending = TRUE;
8830 asc_dvc->sdtr_done = 0;
8831 saved_ctrl_reg &= (uchar)(~CC_HALT);
8832 while ((AscGetChipStatus(iop_base) &
8833 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
8834 DvcSleepMilliSecond(100);
8835 }
8836 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
8837 AscSetChipControl(iop_base, CC_HALT);
8838 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
8839 AscSetChipStatus(iop_base, 0);
8840 chipstat = AscGetChipStatus(iop_base);
8841 }
8842 }
8843 saved_ram_addr = AscGetChipLramAddr(iop_base);
8844 host_flag = AscReadLramByte(iop_base,
8845 ASCV_HOST_FLAG_B) &
8846 (uchar)(~ASC_HOST_FLAG_IN_ISR);
8847 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
8848 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
8849 if ((chipstat & CSW_INT_PENDING)
8850 || (int_pending)
8851 ) {
8852 AscAckInterrupt(iop_base);
8853 int_pending = TRUE;
8854 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
8855 if (AscIsrChipHalted(asc_dvc) == ERR) {
8856 goto ISR_REPORT_QDONE_FATAL_ERROR;
8857 } else {
8858 saved_ctrl_reg &= (uchar)(~CC_HALT);
8859 }
8860 } else {
8861 ISR_REPORT_QDONE_FATAL_ERROR:
8862 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
8863 while (((status =
8864 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
8865 }
8866 } else {
8867 do {
8868 if ((status =
8869 AscIsrQDone(asc_dvc)) == 1) {
8870 break;
8871 }
8872 } while (status == 0x11);
8873 }
8874 if ((status & 0x80) != 0)
8875 int_pending = ERR;
8876 }
8877 }
8878 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
8879 AscSetChipLramAddr(iop_base, saved_ram_addr);
8880 AscSetChipControl(iop_base, saved_ctrl_reg);
8881 asc_dvc->is_in_int = FALSE;
8882 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008883}
8884
8885/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008886static uchar _asc_mcode_buf[] = {
8887 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8888 0x00, 0x00, 0x00, 0x00,
8889 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
8890 0x00, 0x00, 0x00, 0x00,
8891 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8892 0x00, 0x00, 0x00, 0x00,
8893 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8894 0x00, 0x00, 0x00, 0x00,
8895 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
8896 0x00, 0xFF, 0x00, 0x00,
8897 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
8898 0x00, 0x00, 0x00, 0x00,
8899 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
8900 0x00, 0x00, 0x00, 0x00,
8901 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
8902 0x00, 0x00, 0x00, 0x00,
8903 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
8904 0x03, 0x23, 0x36, 0x40,
8905 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
8906 0xC2, 0x00, 0x92, 0x80,
8907 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
8908 0xB6, 0x00, 0x92, 0x80,
8909 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
8910 0x92, 0x80, 0x80, 0x62,
8911 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
8912 0xCD, 0x04, 0x4D, 0x00,
8913 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
8914 0xE6, 0x84, 0xD2, 0xC1,
8915 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
8916 0xC6, 0x81, 0xC2, 0x88,
8917 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
8918 0x84, 0x97, 0x07, 0xA6,
8919 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
8920 0xC2, 0x88, 0xCE, 0x00,
8921 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
8922 0x80, 0x63, 0x07, 0xA6,
8923 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
8924 0x34, 0x01, 0x00, 0x33,
8925 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
8926 0x68, 0x98, 0x4D, 0x04,
8927 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
8928 0xF8, 0x88, 0xFB, 0x23,
8929 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
8930 0x00, 0x33, 0x0A, 0x00,
8931 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
8932 0xC2, 0x88, 0xCD, 0x04,
8933 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
8934 0x06, 0xAB, 0x82, 0x01,
8935 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
8936 0x3C, 0x01, 0x00, 0x05,
8937 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
8938 0x15, 0x23, 0xA1, 0x01,
8939 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
8940 0x06, 0x61, 0x00, 0xA0,
8941 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
8942 0xC2, 0x88, 0x06, 0x23,
8943 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
8944 0x57, 0x60, 0x00, 0xA0,
8945 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
8946 0x4B, 0x00, 0x06, 0x61,
8947 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
8948 0x4F, 0x00, 0x84, 0x97,
8949 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
8950 0x48, 0x04, 0x84, 0x80,
8951 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
8952 0x81, 0x73, 0x06, 0x29,
8953 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
8954 0x04, 0x98, 0xF0, 0x80,
8955 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
8956 0x34, 0x02, 0x03, 0xA6,
8957 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
8958 0x46, 0x82, 0xFE, 0x95,
8959 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
8960 0x07, 0xA6, 0x5A, 0x02,
8961 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
8962 0x48, 0x82, 0x60, 0x96,
8963 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
8964 0x04, 0x01, 0x0C, 0xDC,
8965 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
8966 0x6F, 0x00, 0xA5, 0x01,
8967 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
8968 0x02, 0xA6, 0xAA, 0x02,
8969 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
8970 0x01, 0xA6, 0xB4, 0x02,
8971 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
8972 0x80, 0x63, 0x00, 0x43,
8973 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
8974 0x04, 0x61, 0x84, 0x01,
8975 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
8976 0x00, 0x00, 0xEA, 0x82,
8977 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
8978 0x00, 0x33, 0x1F, 0x00,
8979 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
8980 0xB6, 0x2D, 0x01, 0xA6,
8981 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
8982 0x10, 0x03, 0x03, 0xA6,
8983 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
8984 0x7C, 0x95, 0xEE, 0x82,
8985 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
8986 0x04, 0x01, 0x2D, 0xC8,
8987 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
8988 0x05, 0x05, 0x86, 0x98,
8989 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
8990 0x3C, 0x04, 0x06, 0xA6,
8991 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
8992 0x7C, 0x95, 0x32, 0x83,
8993 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
8994 0xEB, 0x04, 0x00, 0x33,
8995 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
8996 0xFF, 0xA2, 0x7A, 0x03,
8997 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
8998 0x00, 0xA2, 0x9A, 0x03,
8999 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
9000 0x01, 0xA6, 0x96, 0x03,
9001 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
9002 0xA4, 0x03, 0x00, 0xA6,
9003 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
9004 0x07, 0xA6, 0xB2, 0x03,
9005 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
9006 0xA8, 0x98, 0x80, 0x42,
9007 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
9008 0xC0, 0x83, 0x00, 0x33,
9009 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
9010 0xA0, 0x01, 0x12, 0x23,
9011 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
9012 0x80, 0x67, 0x05, 0x23,
9013 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
9014 0x06, 0xA6, 0x0A, 0x04,
9015 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
9016 0xF4, 0x83, 0x20, 0x84,
9017 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
9018 0x83, 0x03, 0x80, 0x63,
9019 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
9020 0x38, 0x04, 0x00, 0x33,
9021 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
9022 0x1D, 0x01, 0x06, 0xCC,
9023 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
9024 0xA2, 0x0D, 0x80, 0x63,
9025 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
9026 0x80, 0x63, 0xA3, 0x01,
9027 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
9028 0x76, 0x04, 0xE0, 0x00,
9029 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
9030 0x00, 0x33, 0x1E, 0x00,
9031 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
9032 0x08, 0x23, 0x22, 0xA3,
9033 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
9034 0xC4, 0x04, 0x42, 0x23,
9035 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
9036 0xF8, 0x88, 0x04, 0x98,
9037 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
9038 0x81, 0x62, 0xE8, 0x81,
9039 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
9040 0x00, 0x33, 0x00, 0x81,
9041 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
9042 0xF8, 0x88, 0x04, 0x23,
9043 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
9044 0xF4, 0x04, 0x00, 0x33,
9045 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9046 0x04, 0x23, 0xA0, 0x01,
9047 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9048 0x00, 0xA3, 0x22, 0x05,
9049 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9050 0x46, 0x97, 0xCD, 0x04,
9051 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9052 0x82, 0x01, 0x34, 0x85,
9053 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9054 0x1D, 0x01, 0x04, 0xD6,
9055 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9056 0x49, 0x00, 0x81, 0x01,
9057 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9058 0x49, 0x04, 0x80, 0x01,
9059 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9060 0x01, 0x23, 0xEA, 0x00,
9061 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9062 0x07, 0xA4, 0xF8, 0x05,
9063 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9064 0xC2, 0x88, 0x04, 0xA0,
9065 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9066 0x00, 0xA2, 0xA4, 0x05,
9067 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9068 0x62, 0x97, 0x04, 0x85,
9069 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9070 0xF4, 0x85, 0x03, 0xA0,
9071 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9072 0xCC, 0x86, 0x07, 0xA0,
9073 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9074 0x80, 0x67, 0x80, 0x63,
9075 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9076 0xF8, 0x88, 0x07, 0x23,
9077 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9078 0x00, 0x63, 0x4A, 0x00,
9079 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9080 0x07, 0x41, 0x83, 0x03,
9081 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9082 0x1D, 0x01, 0x01, 0xD6,
9083 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9084 0x07, 0xA6, 0x7C, 0x05,
9085 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9086 0x52, 0x00, 0x06, 0x61,
9087 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9088 0x00, 0x63, 0x1D, 0x01,
9089 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9090 0x07, 0x41, 0x00, 0x63,
9091 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9092 0xDF, 0x00, 0x06, 0xA6,
9093 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9094 0x00, 0x40, 0xC0, 0x20,
9095 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9096 0x06, 0xA6, 0x94, 0x06,
9097 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9098 0x40, 0x0E, 0x80, 0x63,
9099 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9100 0x80, 0x63, 0x00, 0x43,
9101 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9102 0x80, 0x67, 0x40, 0x0E,
9103 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9104 0x07, 0xA6, 0xD6, 0x06,
9105 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9106 0x0A, 0x2B, 0x07, 0xA6,
9107 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9108 0xF4, 0x06, 0xC0, 0x0E,
9109 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9110 0x81, 0x62, 0x04, 0x01,
9111 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9112 0x8C, 0x06, 0x00, 0x33,
9113 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9114 0x80, 0x63, 0x06, 0xA6,
9115 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9116 0x00, 0x00, 0x80, 0x67,
9117 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9118 0xBF, 0x23, 0x04, 0x61,
9119 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9120 0x00, 0x01, 0xF2, 0x00,
9121 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9122 0x80, 0x05, 0x81, 0x05,
9123 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9124 0x70, 0x00, 0x81, 0x01,
9125 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9126 0x70, 0x00, 0x80, 0x01,
9127 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9128 0xF1, 0x00, 0x70, 0x00,
9129 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9130 0x71, 0x04, 0x70, 0x00,
9131 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9132 0xA3, 0x01, 0xA2, 0x01,
9133 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9134 0xC4, 0x07, 0x00, 0x33,
9135 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9136 0x48, 0x00, 0xB0, 0x01,
9137 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9138 0x00, 0xA2, 0xE4, 0x07,
9139 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9140 0x05, 0x05, 0x00, 0x63,
9141 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9142 0x76, 0x08, 0x80, 0x02,
9143 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9144 0x00, 0x02, 0x00, 0xA0,
9145 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9146 0x00, 0x63, 0xF3, 0x04,
9147 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9148 0x00, 0xA2, 0x44, 0x08,
9149 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9150 0x24, 0x08, 0x04, 0x98,
9151 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9152 0x5A, 0x88, 0x02, 0x01,
9153 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9154 0x00, 0xA3, 0x64, 0x08,
9155 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9156 0x06, 0xA6, 0x76, 0x08,
9157 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9158 0x00, 0x63, 0x38, 0x2B,
9159 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9160 0x05, 0x05, 0xB2, 0x09,
9161 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9162 0x80, 0x32, 0x80, 0x36,
9163 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9164 0x40, 0x36, 0x40, 0x3A,
9165 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9166 0x5D, 0x00, 0xFE, 0xC3,
9167 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9168 0xFF, 0xFD, 0x80, 0x73,
9169 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9170 0xA1, 0x23, 0xA1, 0x01,
9171 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9172 0x80, 0x00, 0x03, 0xC2,
9173 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9174 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009175};
9176
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009177static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9178static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009179
9180#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009181static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9182 INQUIRY,
9183 REQUEST_SENSE,
9184 READ_CAPACITY,
9185 READ_TOC,
9186 MODE_SELECT,
9187 MODE_SENSE,
9188 MODE_SELECT_10,
9189 MODE_SENSE_10,
9190 0xFF,
9191 0xFF,
9192 0xFF,
9193 0xFF,
9194 0xFF,
9195 0xFF,
9196 0xFF,
9197 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009198};
9199
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009200static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009201{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009202 PortAddr iop_base;
9203 ulong last_int_level;
9204 int sta;
9205 int n_q_required;
9206 int disable_syn_offset_one_fix;
9207 int i;
9208 ASC_PADDR addr;
9209 ASC_EXE_CALLBACK asc_exe_callback;
9210 ushort sg_entry_cnt = 0;
9211 ushort sg_entry_cnt_minus_one = 0;
9212 uchar target_ix;
9213 uchar tid_no;
9214 uchar sdtr_data;
9215 uchar extra_bytes;
9216 uchar scsi_cmd;
9217 uchar disable_cmd;
9218 ASC_SG_HEAD *sg_head;
9219 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009220
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009221 iop_base = asc_dvc->iop_base;
9222 sg_head = scsiq->sg_head;
9223 asc_exe_callback = asc_dvc->exe_callback;
9224 if (asc_dvc->err_code != 0)
9225 return (ERR);
9226 if (scsiq == (ASC_SCSI_Q *)0L) {
9227 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9228 return (ERR);
9229 }
9230 scsiq->q1.q_no = 0;
9231 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9232 scsiq->q1.extra_bytes = 0;
9233 }
9234 sta = 0;
9235 target_ix = scsiq->q2.target_ix;
9236 tid_no = ASC_TIX_TO_TID(target_ix);
9237 n_q_required = 1;
9238 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9239 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9240 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9241 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9242 AscMsgOutSDTR(asc_dvc,
9243 asc_dvc->
9244 sdtr_period_tbl[(sdtr_data >> 4) &
9245 (uchar)(asc_dvc->
9246 max_sdtr_index -
9247 1)],
9248 (uchar)(sdtr_data & (uchar)
9249 ASC_SYN_MAX_OFFSET));
9250 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9251 }
9252 }
9253 last_int_level = DvcEnterCritical();
9254 if (asc_dvc->in_critical_cnt != 0) {
9255 DvcLeaveCritical(last_int_level);
9256 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9257 return (ERR);
9258 }
9259 asc_dvc->in_critical_cnt++;
9260 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9261 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9262 asc_dvc->in_critical_cnt--;
9263 DvcLeaveCritical(last_int_level);
9264 return (ERR);
9265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009266#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009267 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9268 asc_dvc->in_critical_cnt--;
9269 DvcLeaveCritical(last_int_level);
9270 return (ERR);
9271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009272#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009273 if (sg_entry_cnt == 1) {
9274 scsiq->q1.data_addr =
9275 (ADV_PADDR)sg_head->sg_list[0].addr;
9276 scsiq->q1.data_cnt =
9277 (ADV_DCNT)sg_head->sg_list[0].bytes;
9278 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9279 }
9280 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9281 }
9282 scsi_cmd = scsiq->cdbptr[0];
9283 disable_syn_offset_one_fix = FALSE;
9284 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9285 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9286 if (scsiq->q1.cntl & QC_SG_HEAD) {
9287 data_cnt = 0;
9288 for (i = 0; i < sg_entry_cnt; i++) {
9289 data_cnt +=
9290 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9291 bytes);
9292 }
9293 } else {
9294 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9295 }
9296 if (data_cnt != 0UL) {
9297 if (data_cnt < 512UL) {
9298 disable_syn_offset_one_fix = TRUE;
9299 } else {
9300 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9301 i++) {
9302 disable_cmd =
9303 _syn_offset_one_disable_cmd[i];
9304 if (disable_cmd == 0xFF) {
9305 break;
9306 }
9307 if (scsi_cmd == disable_cmd) {
9308 disable_syn_offset_one_fix =
9309 TRUE;
9310 break;
9311 }
9312 }
9313 }
9314 }
9315 }
9316 if (disable_syn_offset_one_fix) {
9317 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9318 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9319 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9320 } else {
9321 scsiq->q2.tag_code &= 0x27;
9322 }
9323 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9324 if (asc_dvc->bug_fix_cntl) {
9325 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9326 if ((scsi_cmd == READ_6) ||
9327 (scsi_cmd == READ_10)) {
9328 addr =
9329 (ADV_PADDR)le32_to_cpu(sg_head->
9330 sg_list
9331 [sg_entry_cnt_minus_one].
9332 addr) +
9333 (ADV_DCNT)le32_to_cpu(sg_head->
9334 sg_list
9335 [sg_entry_cnt_minus_one].
9336 bytes);
9337 extra_bytes =
9338 (uchar)((ushort)addr & 0x0003);
9339 if ((extra_bytes != 0)
9340 &&
9341 ((scsiq->q2.
9342 tag_code &
9343 ASC_TAG_FLAG_EXTRA_BYTES)
9344 == 0)) {
9345 scsiq->q2.tag_code |=
9346 ASC_TAG_FLAG_EXTRA_BYTES;
9347 scsiq->q1.extra_bytes =
9348 extra_bytes;
9349 data_cnt =
9350 le32_to_cpu(sg_head->
9351 sg_list
9352 [sg_entry_cnt_minus_one].
9353 bytes);
9354 data_cnt -=
9355 (ASC_DCNT) extra_bytes;
9356 sg_head->
9357 sg_list
9358 [sg_entry_cnt_minus_one].
9359 bytes =
9360 cpu_to_le32(data_cnt);
9361 }
9362 }
9363 }
9364 }
9365 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009366#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009367 /*
9368 * Set the sg_entry_cnt to the maximum possible. The rest of
9369 * the SG elements will be copied when the RISC completes the
9370 * SG elements that fit and halts.
9371 */
9372 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9373 sg_entry_cnt = ASC_MAX_SG_LIST;
9374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009375#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009376 n_q_required = AscSgListToQueue(sg_entry_cnt);
9377 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9378 (uint) n_q_required)
9379 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9380 if ((sta =
9381 AscSendScsiQueue(asc_dvc, scsiq,
9382 n_q_required)) == 1) {
9383 asc_dvc->in_critical_cnt--;
9384 if (asc_exe_callback != 0) {
9385 (*asc_exe_callback) (asc_dvc, scsiq);
9386 }
9387 DvcLeaveCritical(last_int_level);
9388 return (sta);
9389 }
9390 }
9391 } else {
9392 if (asc_dvc->bug_fix_cntl) {
9393 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9394 if ((scsi_cmd == READ_6) ||
9395 (scsi_cmd == READ_10)) {
9396 addr =
9397 le32_to_cpu(scsiq->q1.data_addr) +
9398 le32_to_cpu(scsiq->q1.data_cnt);
9399 extra_bytes =
9400 (uchar)((ushort)addr & 0x0003);
9401 if ((extra_bytes != 0)
9402 &&
9403 ((scsiq->q2.
9404 tag_code &
9405 ASC_TAG_FLAG_EXTRA_BYTES)
9406 == 0)) {
9407 data_cnt =
9408 le32_to_cpu(scsiq->q1.
9409 data_cnt);
9410 if (((ushort)data_cnt & 0x01FF)
9411 == 0) {
9412 scsiq->q2.tag_code |=
9413 ASC_TAG_FLAG_EXTRA_BYTES;
9414 data_cnt -= (ASC_DCNT)
9415 extra_bytes;
9416 scsiq->q1.data_cnt =
9417 cpu_to_le32
9418 (data_cnt);
9419 scsiq->q1.extra_bytes =
9420 extra_bytes;
9421 }
9422 }
9423 }
9424 }
9425 }
9426 n_q_required = 1;
9427 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9428 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9429 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9430 n_q_required)) == 1) {
9431 asc_dvc->in_critical_cnt--;
9432 if (asc_exe_callback != 0) {
9433 (*asc_exe_callback) (asc_dvc, scsiq);
9434 }
9435 DvcLeaveCritical(last_int_level);
9436 return (sta);
9437 }
9438 }
9439 }
9440 asc_dvc->in_critical_cnt--;
9441 DvcLeaveCritical(last_int_level);
9442 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009443}
9444
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009445static int
9446AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009447{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009448 PortAddr iop_base;
9449 uchar free_q_head;
9450 uchar next_qp;
9451 uchar tid_no;
9452 uchar target_ix;
9453 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009454
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009455 iop_base = asc_dvc->iop_base;
9456 target_ix = scsiq->q2.target_ix;
9457 tid_no = ASC_TIX_TO_TID(target_ix);
9458 sta = 0;
9459 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9460 if (n_q_required > 1) {
9461 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9462 free_q_head, (uchar)
9463 (n_q_required)))
9464 != (uchar)ASC_QLINK_END) {
9465 asc_dvc->last_q_shortage = 0;
9466 scsiq->sg_head->queue_cnt = n_q_required - 1;
9467 scsiq->q1.q_no = free_q_head;
9468 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9469 free_q_head)) == 1) {
9470 AscPutVarFreeQHead(iop_base, next_qp);
9471 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9472 asc_dvc->cur_dvc_qng[tid_no]++;
9473 }
9474 return (sta);
9475 }
9476 } else if (n_q_required == 1) {
9477 if ((next_qp = AscAllocFreeQueue(iop_base,
9478 free_q_head)) !=
9479 ASC_QLINK_END) {
9480 scsiq->q1.q_no = free_q_head;
9481 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9482 free_q_head)) == 1) {
9483 AscPutVarFreeQHead(iop_base, next_qp);
9484 asc_dvc->cur_total_qng++;
9485 asc_dvc->cur_dvc_qng[tid_no]++;
9486 }
9487 return (sta);
9488 }
9489 }
9490 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009491}
9492
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009493static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009494{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009495 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009496
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009497 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9498 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9499 n_sg_list_qs++;
9500 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009501}
9502
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009503static uint
9504AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009505{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009506 uint cur_used_qs;
9507 uint cur_free_qs;
9508 ASC_SCSI_BIT_ID_TYPE target_id;
9509 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009510
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009511 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9512 tid_no = ASC_TIX_TO_TID(target_ix);
9513 if ((asc_dvc->unit_not_ready & target_id) ||
9514 (asc_dvc->queue_full_or_busy & target_id)) {
9515 return (0);
9516 }
9517 if (n_qs == 1) {
9518 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9519 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9520 } else {
9521 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9522 (uint) ASC_MIN_FREE_Q;
9523 }
9524 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9525 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9526 if (asc_dvc->cur_dvc_qng[tid_no] >=
9527 asc_dvc->max_dvc_qng[tid_no]) {
9528 return (0);
9529 }
9530 return (cur_free_qs);
9531 }
9532 if (n_qs > 1) {
9533 if ((n_qs > asc_dvc->last_q_shortage)
9534 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9535 asc_dvc->last_q_shortage = n_qs;
9536 }
9537 }
9538 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009539}
9540
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009541static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009542{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009543 ushort q_addr;
9544 uchar tid_no;
9545 uchar sdtr_data;
9546 uchar syn_period_ix;
9547 uchar syn_offset;
9548 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009549
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009550 iop_base = asc_dvc->iop_base;
9551 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9552 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9553 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9554 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9555 syn_period_ix =
9556 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9557 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9558 AscMsgOutSDTR(asc_dvc,
9559 asc_dvc->sdtr_period_tbl[syn_period_ix],
9560 syn_offset);
9561 scsiq->q1.cntl |= QC_MSG_OUT;
9562 }
9563 q_addr = ASC_QNO_TO_QADDR(q_no);
9564 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9565 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9566 }
9567 scsiq->q1.status = QS_FREE;
9568 AscMemWordCopyPtrToLram(iop_base,
9569 q_addr + ASC_SCSIQ_CDB_BEG,
9570 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009571
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009572 DvcPutScsiQ(iop_base,
9573 q_addr + ASC_SCSIQ_CPY_BEG,
9574 (uchar *)&scsiq->q1.cntl,
9575 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9576 AscWriteLramWord(iop_base,
9577 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9578 (ushort)(((ushort)scsiq->q1.
9579 q_no << 8) | (ushort)QS_READY));
9580 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009581}
9582
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009583static int
9584AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009585{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009586 int sta;
9587 int i;
9588 ASC_SG_HEAD *sg_head;
9589 ASC_SG_LIST_Q scsi_sg_q;
9590 ASC_DCNT saved_data_addr;
9591 ASC_DCNT saved_data_cnt;
9592 PortAddr iop_base;
9593 ushort sg_list_dwords;
9594 ushort sg_index;
9595 ushort sg_entry_cnt;
9596 ushort q_addr;
9597 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009598
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009599 iop_base = asc_dvc->iop_base;
9600 sg_head = scsiq->sg_head;
9601 saved_data_addr = scsiq->q1.data_addr;
9602 saved_data_cnt = scsiq->q1.data_cnt;
9603 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9604 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009605#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009606 /*
9607 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9608 * then not all SG elements will fit in the allocated queues.
9609 * The rest of the SG elements will be copied when the RISC
9610 * completes the SG elements that fit and halts.
9611 */
9612 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9613 /*
9614 * Set sg_entry_cnt to be the number of SG elements that
9615 * will fit in the allocated SG queues. It is minus 1, because
9616 * the first SG element is handled above. ASC_MAX_SG_LIST is
9617 * already inflated by 1 to account for this. For example it
9618 * may be 50 which is 1 + 7 queues * 7 SG elements.
9619 */
9620 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009621
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009622 /*
9623 * Keep track of remaining number of SG elements that will
9624 * need to be handled from a_isr.c.
9625 */
9626 scsiq->remain_sg_entry_cnt =
9627 sg_head->entry_cnt - ASC_MAX_SG_LIST;
9628 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009629#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009630 /*
9631 * Set sg_entry_cnt to be the number of SG elements that
9632 * will fit in the allocated SG queues. It is minus 1, because
9633 * the first SG element is handled above.
9634 */
9635 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009636#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009638#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009639 if (sg_entry_cnt != 0) {
9640 scsiq->q1.cntl |= QC_SG_HEAD;
9641 q_addr = ASC_QNO_TO_QADDR(q_no);
9642 sg_index = 1;
9643 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
9644 scsi_sg_q.sg_head_qp = q_no;
9645 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
9646 for (i = 0; i < sg_head->queue_cnt; i++) {
9647 scsi_sg_q.seq_no = i + 1;
9648 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
9649 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
9650 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
9651 if (i == 0) {
9652 scsi_sg_q.sg_list_cnt =
9653 ASC_SG_LIST_PER_Q;
9654 scsi_sg_q.sg_cur_list_cnt =
9655 ASC_SG_LIST_PER_Q;
9656 } else {
9657 scsi_sg_q.sg_list_cnt =
9658 ASC_SG_LIST_PER_Q - 1;
9659 scsi_sg_q.sg_cur_list_cnt =
9660 ASC_SG_LIST_PER_Q - 1;
9661 }
9662 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009663#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009664 /*
9665 * This is the last SG queue in the list of
9666 * allocated SG queues. If there are more
9667 * SG elements than will fit in the allocated
9668 * queues, then set the QCSG_SG_XFER_MORE flag.
9669 */
9670 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9671 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
9672 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009673#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009674 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009675#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009676 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009677#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009678 sg_list_dwords = sg_entry_cnt << 1;
9679 if (i == 0) {
9680 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
9681 scsi_sg_q.sg_cur_list_cnt =
9682 sg_entry_cnt;
9683 } else {
9684 scsi_sg_q.sg_list_cnt =
9685 sg_entry_cnt - 1;
9686 scsi_sg_q.sg_cur_list_cnt =
9687 sg_entry_cnt - 1;
9688 }
9689 sg_entry_cnt = 0;
9690 }
9691 next_qp = AscReadLramByte(iop_base,
9692 (ushort)(q_addr +
9693 ASC_SCSIQ_B_FWD));
9694 scsi_sg_q.q_no = next_qp;
9695 q_addr = ASC_QNO_TO_QADDR(next_qp);
9696 AscMemWordCopyPtrToLram(iop_base,
9697 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
9698 (uchar *)&scsi_sg_q,
9699 sizeof(ASC_SG_LIST_Q) >> 1);
9700 AscMemDWordCopyPtrToLram(iop_base,
9701 q_addr + ASC_SGQ_LIST_BEG,
9702 (uchar *)&sg_head->
9703 sg_list[sg_index],
9704 sg_list_dwords);
9705 sg_index += ASC_SG_LIST_PER_Q;
9706 scsiq->next_sg_index = sg_index;
9707 }
9708 } else {
9709 scsiq->q1.cntl &= ~QC_SG_HEAD;
9710 }
9711 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
9712 scsiq->q1.data_addr = saved_data_addr;
9713 scsiq->q1.data_cnt = saved_data_cnt;
9714 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009715}
9716
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009717static int
9718AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009719{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009720 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009721
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009722 if (AscHostReqRiscHalt(iop_base)) {
9723 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9724 AscStartChip(iop_base);
9725 return (sta);
9726 }
9727 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009728}
9729
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009730static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009731{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009732 ASC_SCSI_BIT_ID_TYPE org_id;
9733 int i;
9734 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009735
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009736 AscSetBank(iop_base, 1);
9737 org_id = AscReadChipDvcID(iop_base);
9738 for (i = 0; i <= ASC_MAX_TID; i++) {
9739 if (org_id == (0x01 << i))
9740 break;
9741 }
9742 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
9743 AscWriteChipDvcID(iop_base, id);
9744 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
9745 AscSetBank(iop_base, 0);
9746 AscSetChipSyn(iop_base, sdtr_data);
9747 if (AscGetChipSyn(iop_base) != sdtr_data) {
9748 sta = FALSE;
9749 }
9750 } else {
9751 sta = FALSE;
9752 }
9753 AscSetBank(iop_base, 1);
9754 AscWriteChipDvcID(iop_base, org_id);
9755 AscSetBank(iop_base, 0);
9756 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009757}
9758
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009759static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009760{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009761 uchar i;
9762 ushort s_addr;
9763 PortAddr iop_base;
9764 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009765
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009766 iop_base = asc_dvc->iop_base;
9767 warn_code = 0;
9768 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
9769 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
9770 64) >> 1)
9771 );
9772 i = ASC_MIN_ACTIVE_QNO;
9773 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
9774 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9775 (uchar)(i + 1));
9776 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9777 (uchar)(asc_dvc->max_total_qng));
9778 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9779 (uchar)i);
9780 i++;
9781 s_addr += ASC_QBLK_SIZE;
9782 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
9783 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9784 (uchar)(i + 1));
9785 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9786 (uchar)(i - 1));
9787 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9788 (uchar)i);
9789 }
9790 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9791 (uchar)ASC_QLINK_END);
9792 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9793 (uchar)(asc_dvc->max_total_qng - 1));
9794 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9795 (uchar)asc_dvc->max_total_qng);
9796 i++;
9797 s_addr += ASC_QBLK_SIZE;
9798 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
9799 i++, s_addr += ASC_QBLK_SIZE) {
9800 AscWriteLramByte(iop_base,
9801 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
9802 AscWriteLramByte(iop_base,
9803 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
9804 AscWriteLramByte(iop_base,
9805 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
9806 }
9807 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009808}
9809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009810static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009811{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009812 PortAddr iop_base;
9813 int i;
9814 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009815
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009816 iop_base = asc_dvc->iop_base;
9817 AscPutRiscVarFreeQHead(iop_base, 1);
9818 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9819 AscPutVarFreeQHead(iop_base, 1);
9820 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9821 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
9822 (uchar)((int)asc_dvc->max_total_qng + 1));
9823 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
9824 (uchar)((int)asc_dvc->max_total_qng + 2));
9825 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
9826 asc_dvc->max_total_qng);
9827 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
9828 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
9829 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
9830 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
9831 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
9832 AscPutQDoneInProgress(iop_base, 0);
9833 lram_addr = ASC_QADR_BEG;
9834 for (i = 0; i < 32; i++, lram_addr += 2) {
9835 AscWriteLramWord(iop_base, lram_addr, 0);
9836 }
9837 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009838}
9839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009840static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009841{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009842 if (asc_dvc->err_code == 0) {
9843 asc_dvc->err_code = err_code;
9844 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
9845 err_code);
9846 }
9847 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009848}
9849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009850static uchar
9851AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009852{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009853 EXT_MSG sdtr_buf;
9854 uchar sdtr_period_index;
9855 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009857 iop_base = asc_dvc->iop_base;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009858 sdtr_buf.msg_type = EXTENDED_MESSAGE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009859 sdtr_buf.msg_len = MS_SDTR_LEN;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009860 sdtr_buf.msg_req = EXTENDED_SDTR;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009861 sdtr_buf.xfer_period = sdtr_period;
9862 sdtr_offset &= ASC_SYN_MAX_OFFSET;
9863 sdtr_buf.req_ack_offset = sdtr_offset;
9864 if ((sdtr_period_index =
9865 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
9866 asc_dvc->max_sdtr_index) {
9867 AscMemWordCopyPtrToLram(iop_base,
9868 ASCV_MSGOUT_BEG,
9869 (uchar *)&sdtr_buf,
9870 sizeof(EXT_MSG) >> 1);
9871 return ((sdtr_period_index << 4) | sdtr_offset);
9872 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009873
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009874 sdtr_buf.req_ack_offset = 0;
9875 AscMemWordCopyPtrToLram(iop_base,
9876 ASCV_MSGOUT_BEG,
9877 (uchar *)&sdtr_buf,
9878 sizeof(EXT_MSG) >> 1);
9879 return (0);
9880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009881}
9882
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009883static uchar
9884AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009885{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009886 uchar byte;
9887 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009888
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009889 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
9890 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
9891 ) {
9892 return (0xFF);
9893 }
9894 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
9895 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009896}
9897
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009898static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009899{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009900 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9901 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
9902 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009903}
9904
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009905static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009906{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009907 uchar *period_table;
9908 int max_index;
9909 int min_index;
9910 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009911
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009912 period_table = asc_dvc->sdtr_period_tbl;
9913 max_index = (int)asc_dvc->max_sdtr_index;
9914 min_index = (int)asc_dvc->host_init_sdtr_index;
9915 if ((syn_time <= period_table[max_index])) {
9916 for (i = min_index; i < (max_index - 1); i++) {
9917 if (syn_time <= period_table[i]) {
9918 return ((uchar)i);
9919 }
9920 }
9921 return ((uchar)max_index);
9922 } else {
9923 return ((uchar)(max_index + 1));
9924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009925}
9926
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009927static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009928{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009929 ushort q_addr;
9930 uchar next_qp;
9931 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009933 q_addr = ASC_QNO_TO_QADDR(free_q_head);
9934 q_status = (uchar)AscReadLramByte(iop_base,
9935 (ushort)(q_addr +
9936 ASC_SCSIQ_B_STATUS));
9937 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
9938 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
9939 return (next_qp);
9940 }
9941 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009942}
9943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009944static uchar
9945AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009946{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009947 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009948
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009949 for (i = 0; i < n_free_q; i++) {
9950 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
9951 == ASC_QLINK_END) {
9952 return (ASC_QLINK_END);
9953 }
9954 }
9955 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009956}
9957
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009958static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009959{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009960 int count = 0;
9961 int sta = 0;
9962 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009963
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009964 if (AscIsChipHalted(iop_base))
9965 return (1);
9966 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
9967 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9968 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
9969 do {
9970 if (AscIsChipHalted(iop_base)) {
9971 sta = 1;
9972 break;
9973 }
9974 DvcSleepMilliSecond(100);
9975 } while (count++ < 20);
9976 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
9977 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009978}
9979
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009980static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009981{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009982 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009984 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
9985 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9986 ASC_STOP_REQ_RISC_STOP);
9987 do {
9988 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
9989 ASC_STOP_ACK_RISC_STOP) {
9990 return (1);
9991 }
9992 DvcSleepMilliSecond(100);
9993 } while (count++ < 20);
9994 }
9995 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009996}
9997
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009998static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009999{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010000 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010001}
10002
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010003static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010004{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010005 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010006}
10007
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010008static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010009{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010010 AscSetChipControl(iop_base, 0);
10011 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10012 return (0);
10013 }
10014 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010015}
10016
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010017static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010018{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010019 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010020
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010021 cc_val =
10022 AscGetChipControl(iop_base) &
10023 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
10024 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
10025 AscSetChipIH(iop_base, INS_HALT);
10026 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10027 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
10028 return (0);
10029 }
10030 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010031}
10032
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010033static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010034{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010035 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10036 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
10037 return (1);
10038 }
10039 }
10040 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010041}
10042
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010043static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010044{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010045 AscSetBank(iop_base, 1);
10046 AscWriteChipIH(iop_base, ins_code);
10047 AscSetBank(iop_base, 0);
10048 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010049}
10050
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010051static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010052{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010053 uchar host_flag;
10054 uchar risc_flag;
10055 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010056
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010057 loop = 0;
10058 do {
10059 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10060 if (loop++ > 0x7FFF) {
10061 break;
10062 }
10063 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10064 host_flag =
10065 AscReadLramByte(iop_base,
10066 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10067 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10068 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10069 AscSetChipStatus(iop_base, CIW_INT_ACK);
10070 loop = 0;
10071 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10072 AscSetChipStatus(iop_base, CIW_INT_ACK);
10073 if (loop++ > 3) {
10074 break;
10075 }
10076 }
10077 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10078 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010079}
10080
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010081static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010082{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010083 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010084
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010085 cfg = AscGetChipCfgLsw(iop_base);
10086 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10087 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010088}
10089
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010090static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010091{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010092 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010094 cfg = AscGetChipCfgLsw(iop_base);
10095 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10096 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010097}
10098
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010099static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010100{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010101 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010102
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010103 val = AscGetChipControl(iop_base) &
10104 (~
10105 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10106 CC_CHIP_RESET));
10107 if (bank == 1) {
10108 val |= CC_BANK_ONE;
10109 } else if (bank == 2) {
10110 val |= CC_DIAG | CC_BANK_ONE;
10111 } else {
10112 val &= ~CC_BANK_ONE;
10113 }
10114 AscSetChipControl(iop_base, val);
10115 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010116}
10117
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010118static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010119{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010120 PortAddr iop_base;
10121 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010122
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010123 iop_base = asc_dvc->iop_base;
10124 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10125 && (i-- > 0)) {
10126 DvcSleepMilliSecond(100);
10127 }
10128 AscStopChip(iop_base);
10129 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10130 DvcDelayNanoSecond(asc_dvc, 60000);
10131 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10132 AscSetChipIH(iop_base, INS_HALT);
10133 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10134 AscSetChipControl(iop_base, CC_HALT);
10135 DvcSleepMilliSecond(200);
10136 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10137 AscSetChipStatus(iop_base, 0);
10138 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010139}
10140
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010141static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010142{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010143 if (bus_type & ASC_IS_ISA)
10144 return (ASC_MAX_ISA_DMA_COUNT);
10145 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10146 return (ASC_MAX_VL_DMA_COUNT);
10147 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010148}
10149
10150#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010151static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010152{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010153 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010154
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010155 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10156 if (channel == 0x03)
10157 return (0);
10158 else if (channel == 0x00)
10159 return (7);
10160 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010161}
10162
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010163static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010164{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010165 ushort cfg_lsw;
10166 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010167
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010168 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10169 if (dma_channel == 7)
10170 value = 0x00;
10171 else
10172 value = dma_channel - 4;
10173 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10174 cfg_lsw |= value;
10175 AscSetChipCfgLsw(iop_base, cfg_lsw);
10176 return (AscGetIsaDmaChannel(iop_base));
10177 }
10178 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010179}
10180
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010181static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010182{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010183 speed_value &= 0x07;
10184 AscSetBank(iop_base, 1);
10185 AscWriteChipDmaSpeed(iop_base, speed_value);
10186 AscSetBank(iop_base, 0);
10187 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010188}
10189
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010190static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010191{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010192 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010193
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010194 AscSetBank(iop_base, 1);
10195 speed_value = AscReadChipDmaSpeed(iop_base);
10196 speed_value &= 0x07;
10197 AscSetBank(iop_base, 0);
10198 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010199}
10200#endif /* CONFIG_ISA */
10201
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010202static ushort __devinit AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010203{
Matthew Wilcox9649af32007-07-26 21:51:47 -060010204 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010205
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010206 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -060010207 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010208 return (UW_ERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010209
Matthew Wilcox9649af32007-07-26 21:51:47 -060010210 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010211 warn_code |= AscInitAscDvcVar(asc_dvc);
10212 warn_code |= AscInitFromEEP(asc_dvc);
10213 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010214 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010215 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010216 } else {
10217 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10218 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010219 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010220}
10221
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010222static ushort __devinit AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010223{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010224 ushort warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010225
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010226 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10227 if (asc_dvc->err_code != 0)
10228 return (UW_ERR);
10229 if (AscFindSignature(asc_dvc->iop_base)) {
10230 warn_code |= AscInitFromAscDvcVar(asc_dvc);
10231 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10232 } else {
10233 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10234 }
10235 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010236}
10237
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010238static ushort __devinit AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010239{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010240 PortAddr iop_base;
10241 ushort cfg_msw;
10242 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010243
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010244 iop_base = asc_dvc->iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010245 warn_code = 0;
10246 cfg_msw = AscGetChipCfgMsw(iop_base);
10247 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10248 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10249 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10250 AscSetChipCfgMsw(iop_base, cfg_msw);
10251 }
10252 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10253 asc_dvc->cfg->cmd_qng_enabled) {
10254 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10255 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10256 }
10257 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10258 warn_code |= ASC_WARN_AUTO_CONFIG;
10259 }
10260 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10261 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10262 != asc_dvc->irq_no) {
10263 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10264 }
10265 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010266#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010267 if (asc_dvc->bus_type & ASC_IS_PCI) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010268 struct pci_dev *pdev = to_pci_dev(asc_dvc->cfg->dev);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010269 cfg_msw &= 0xFFC0;
10270 AscSetChipCfgMsw(iop_base, cfg_msw);
10271 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10272 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010273 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
10274 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010275 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10276 asc_dvc->bug_fix_cntl |=
10277 ASC_BUG_FIX_ASYN_USE_SYN;
10278 }
10279 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010280 } else
10281#endif /* CONFIG_PCI */
10282 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010283 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10284 == ASC_CHIP_VER_ASYN_BUG) {
10285 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10286 }
10287 }
10288 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10289 asc_dvc->cfg->chip_scsi_id) {
10290 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010292#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010293 if (asc_dvc->bus_type & ASC_IS_ISA) {
10294 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10295 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010297#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010298 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010299}
10300
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010301static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010302{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010303 ushort warn_code;
10304 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010306 iop_base = asc_dvc->iop_base;
10307 warn_code = 0;
10308 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10309 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10310 AscResetChipAndScsiBus(asc_dvc);
10311 DvcSleepMilliSecond((ASC_DCNT)
10312 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10313 }
10314 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10315 if (asc_dvc->err_code != 0)
10316 return (UW_ERR);
10317 if (!AscFindSignature(asc_dvc->iop_base)) {
10318 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10319 return (warn_code);
10320 }
10321 AscDisableInterrupt(iop_base);
10322 warn_code |= AscInitLram(asc_dvc);
10323 if (asc_dvc->err_code != 0)
10324 return (UW_ERR);
10325 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10326 (ulong)_asc_mcode_chksum);
10327 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10328 _asc_mcode_size) != _asc_mcode_chksum) {
10329 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10330 return (warn_code);
10331 }
10332 warn_code |= AscInitMicroCodeVar(asc_dvc);
10333 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10334 AscEnableInterrupt(iop_base);
10335 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010336}
10337
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010338static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010339{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010340 int i;
10341 PortAddr iop_base;
10342 ushort warn_code;
10343 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010344
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010345 iop_base = asc_dvc->iop_base;
10346 warn_code = 0;
10347 asc_dvc->err_code = 0;
10348 if ((asc_dvc->bus_type &
10349 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10350 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10351 }
10352 AscSetChipControl(iop_base, CC_HALT);
10353 AscSetChipStatus(iop_base, 0);
10354 asc_dvc->bug_fix_cntl = 0;
10355 asc_dvc->pci_fix_asyn_xfer = 0;
10356 asc_dvc->pci_fix_asyn_xfer_always = 0;
10357 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10358 asc_dvc->sdtr_done = 0;
10359 asc_dvc->cur_total_qng = 0;
10360 asc_dvc->is_in_int = 0;
10361 asc_dvc->in_critical_cnt = 0;
10362 asc_dvc->last_q_shortage = 0;
10363 asc_dvc->use_tagged_qng = 0;
10364 asc_dvc->no_scam = 0;
10365 asc_dvc->unit_not_ready = 0;
10366 asc_dvc->queue_full_or_busy = 0;
10367 asc_dvc->redo_scam = 0;
10368 asc_dvc->res2 = 0;
10369 asc_dvc->host_init_sdtr_index = 0;
10370 asc_dvc->cfg->can_tagged_qng = 0;
10371 asc_dvc->cfg->cmd_qng_enabled = 0;
10372 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10373 asc_dvc->init_sdtr = 0;
10374 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10375 asc_dvc->scsi_reset_wait = 3;
10376 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10377 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10378 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10379 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10380 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10381 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10382 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10383 ASC_LIB_VERSION_MINOR;
10384 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10385 asc_dvc->cfg->chip_version = chip_version;
10386 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10387 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10388 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10389 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10390 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10391 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10392 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10393 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10394 asc_dvc->max_sdtr_index = 7;
10395 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10396 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10397 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10398 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10399 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10400 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10401 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10402 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10403 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10404 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10405 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10406 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10407 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10408 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10409 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10410 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10411 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10412 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10413 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10414 asc_dvc->max_sdtr_index = 15;
10415 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10416 AscSetExtraControl(iop_base,
10417 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10418 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10419 AscSetExtraControl(iop_base,
10420 (SEC_ACTIVE_NEGATE |
10421 SEC_ENABLE_FILTER));
10422 }
10423 }
10424 if (asc_dvc->bus_type == ASC_IS_PCI) {
10425 AscSetExtraControl(iop_base,
10426 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010428
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010429 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010430#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010431 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
Matthew Wilcox59fcf842007-07-26 11:54:15 -040010432 if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
10433 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10434 asc_dvc->bus_type = ASC_IS_ISAPNP;
10435 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010436 asc_dvc->cfg->isa_dma_channel =
10437 (uchar)AscGetIsaDmaChannel(iop_base);
10438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010439#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010440 for (i = 0; i <= ASC_MAX_TID; i++) {
10441 asc_dvc->cur_dvc_qng[i] = 0;
10442 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10443 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10444 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10445 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10446 }
10447 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010448}
10449
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010450static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010451{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010452 ASCEEP_CONFIG eep_config_buf;
10453 ASCEEP_CONFIG *eep_config;
10454 PortAddr iop_base;
10455 ushort chksum;
10456 ushort warn_code;
10457 ushort cfg_msw, cfg_lsw;
10458 int i;
10459 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010460
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010461 iop_base = asc_dvc->iop_base;
10462 warn_code = 0;
10463 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10464 AscStopQueueExe(iop_base);
10465 if ((AscStopChip(iop_base) == FALSE) ||
10466 (AscGetChipScsiCtrl(iop_base) != 0)) {
10467 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10468 AscResetChipAndScsiBus(asc_dvc);
10469 DvcSleepMilliSecond((ASC_DCNT)
10470 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10471 }
10472 if (AscIsChipHalted(iop_base) == FALSE) {
10473 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10474 return (warn_code);
10475 }
10476 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10477 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10478 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10479 return (warn_code);
10480 }
10481 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10482 cfg_msw = AscGetChipCfgMsw(iop_base);
10483 cfg_lsw = AscGetChipCfgLsw(iop_base);
10484 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10485 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10486 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10487 AscSetChipCfgMsw(iop_base, cfg_msw);
10488 }
10489 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
10490 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
10491 if (chksum == 0) {
10492 chksum = 0xaa55;
10493 }
10494 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10495 warn_code |= ASC_WARN_AUTO_CONFIG;
10496 if (asc_dvc->cfg->chip_version == 3) {
10497 if (eep_config->cfg_lsw != cfg_lsw) {
10498 warn_code |= ASC_WARN_EEPROM_RECOVER;
10499 eep_config->cfg_lsw =
10500 AscGetChipCfgLsw(iop_base);
10501 }
10502 if (eep_config->cfg_msw != cfg_msw) {
10503 warn_code |= ASC_WARN_EEPROM_RECOVER;
10504 eep_config->cfg_msw =
10505 AscGetChipCfgMsw(iop_base);
10506 }
10507 }
10508 }
10509 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
10510 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
10511 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
10512 eep_config->chksum);
10513 if (chksum != eep_config->chksum) {
10514 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
10515 ASC_CHIP_VER_PCI_ULTRA_3050) {
10516 ASC_DBG(1,
10517 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
10518 eep_config->init_sdtr = 0xFF;
10519 eep_config->disc_enable = 0xFF;
10520 eep_config->start_motor = 0xFF;
10521 eep_config->use_cmd_qng = 0;
10522 eep_config->max_total_qng = 0xF0;
10523 eep_config->max_tag_qng = 0x20;
10524 eep_config->cntl = 0xBFFF;
10525 ASC_EEP_SET_CHIP_ID(eep_config, 7);
10526 eep_config->no_scam = 0;
10527 eep_config->adapter_info[0] = 0;
10528 eep_config->adapter_info[1] = 0;
10529 eep_config->adapter_info[2] = 0;
10530 eep_config->adapter_info[3] = 0;
10531 eep_config->adapter_info[4] = 0;
10532 /* Indicate EEPROM-less board. */
10533 eep_config->adapter_info[5] = 0xBB;
10534 } else {
10535 ASC_PRINT
10536 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
10537 write_eep = 1;
10538 warn_code |= ASC_WARN_EEPROM_CHKSUM;
10539 }
10540 }
10541 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
10542 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
10543 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
10544 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
10545 asc_dvc->start_motor = eep_config->start_motor;
10546 asc_dvc->dvc_cntl = eep_config->cntl;
10547 asc_dvc->no_scam = eep_config->no_scam;
10548 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
10549 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
10550 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
10551 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
10552 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
10553 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
10554 if (!AscTestExternalLram(asc_dvc)) {
10555 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
10556 ASC_IS_PCI_ULTRA)) {
10557 eep_config->max_total_qng =
10558 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
10559 eep_config->max_tag_qng =
10560 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
10561 } else {
10562 eep_config->cfg_msw |= 0x0800;
10563 cfg_msw |= 0x0800;
10564 AscSetChipCfgMsw(iop_base, cfg_msw);
10565 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
10566 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
10567 }
10568 } else {
10569 }
10570 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
10571 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
10572 }
10573 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
10574 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
10575 }
10576 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
10577 eep_config->max_tag_qng = eep_config->max_total_qng;
10578 }
10579 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
10580 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
10581 }
10582 asc_dvc->max_total_qng = eep_config->max_total_qng;
10583 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
10584 eep_config->use_cmd_qng) {
10585 eep_config->disc_enable = eep_config->use_cmd_qng;
10586 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10587 }
10588 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
10589 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
10590 }
10591 ASC_EEP_SET_CHIP_ID(eep_config,
10592 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
10593 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
10594 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
10595 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
10596 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
10597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010598
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010599 for (i = 0; i <= ASC_MAX_TID; i++) {
10600 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
10601 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
10602 asc_dvc->cfg->sdtr_period_offset[i] =
10603 (uchar)(ASC_DEF_SDTR_OFFSET |
10604 (asc_dvc->host_init_sdtr_index << 4));
10605 }
10606 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
10607 if (write_eep) {
10608 if ((i =
10609 AscSetEEPConfig(iop_base, eep_config,
10610 asc_dvc->bus_type)) != 0) {
10611 ASC_PRINT1
10612 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
10613 i);
10614 } else {
10615 ASC_PRINT
10616 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
10617 }
10618 }
10619 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010620}
10621
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010622static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010623{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010624 int i;
10625 ushort warn_code;
10626 PortAddr iop_base;
10627 ASC_PADDR phy_addr;
10628 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010630 iop_base = asc_dvc->iop_base;
10631 warn_code = 0;
10632 for (i = 0; i <= ASC_MAX_TID; i++) {
10633 AscPutMCodeInitSDTRAtID(iop_base, i,
10634 asc_dvc->cfg->sdtr_period_offset[i]
10635 );
10636 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010637
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010638 AscInitQLinkVar(asc_dvc);
10639 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
10640 asc_dvc->cfg->disc_enable);
10641 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
10642 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010643
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010644 /* Align overrun buffer on an 8 byte boundary. */
10645 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
10646 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
10647 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
10648 (uchar *)&phy_addr, 1);
10649 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
10650 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
10651 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010653 asc_dvc->cfg->mcode_date =
10654 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
10655 asc_dvc->cfg->mcode_version =
10656 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010657
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010658 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10659 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10660 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10661 return (warn_code);
10662 }
10663 if (AscStartChip(iop_base) != 1) {
10664 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10665 return (warn_code);
10666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010667
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010668 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010669}
10670
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010671static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010672{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010673 PortAddr iop_base;
10674 ushort q_addr;
10675 ushort saved_word;
10676 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010677
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010678 iop_base = asc_dvc->iop_base;
10679 sta = 0;
10680 q_addr = ASC_QNO_TO_QADDR(241);
10681 saved_word = AscReadLramWord(iop_base, q_addr);
10682 AscSetChipLramAddr(iop_base, q_addr);
10683 AscSetChipLramData(iop_base, 0x55AA);
10684 DvcSleepMilliSecond(10);
10685 AscSetChipLramAddr(iop_base, q_addr);
10686 if (AscGetChipLramData(iop_base) == 0x55AA) {
10687 sta = 1;
10688 AscWriteLramWord(iop_base, q_addr, saved_word);
10689 }
10690 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010691}
10692
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010693static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010694{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010695 uchar read_back;
10696 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010697
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010698 retry = 0;
10699 while (TRUE) {
10700 AscSetChipEEPCmd(iop_base, cmd_reg);
10701 DvcSleepMilliSecond(1);
10702 read_back = AscGetChipEEPCmd(iop_base);
10703 if (read_back == cmd_reg) {
10704 return (1);
10705 }
10706 if (retry++ > ASC_EEP_MAX_RETRY) {
10707 return (0);
10708 }
10709 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010710}
10711
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010712static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010713{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010714 ushort read_back;
10715 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010716
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010717 retry = 0;
10718 while (TRUE) {
10719 AscSetChipEEPData(iop_base, data_reg);
10720 DvcSleepMilliSecond(1);
10721 read_back = AscGetChipEEPData(iop_base);
10722 if (read_back == data_reg) {
10723 return (1);
10724 }
10725 if (retry++ > ASC_EEP_MAX_RETRY) {
10726 return (0);
10727 }
10728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010729}
10730
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010731static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010732{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010733 DvcSleepMilliSecond(1);
10734 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010735}
10736
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010737static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010738{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010739 DvcSleepMilliSecond(20);
10740 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010741}
10742
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010743static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010744{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010745 ushort read_wval;
10746 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010747
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010748 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10749 AscWaitEEPRead();
10750 cmd_reg = addr | ASC_EEP_CMD_READ;
10751 AscWriteEEPCmdReg(iop_base, cmd_reg);
10752 AscWaitEEPRead();
10753 read_wval = AscGetChipEEPData(iop_base);
10754 AscWaitEEPRead();
10755 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010756}
10757
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010758static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010759AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010760{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010761 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010762
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010763 read_wval = AscReadEEPWord(iop_base, addr);
10764 if (read_wval != word_val) {
10765 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
10766 AscWaitEEPRead();
10767 AscWriteEEPDataReg(iop_base, word_val);
10768 AscWaitEEPRead();
10769 AscWriteEEPCmdReg(iop_base,
10770 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
10771 AscWaitEEPWrite();
10772 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10773 AscWaitEEPRead();
10774 return (AscReadEEPWord(iop_base, addr));
10775 }
10776 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010777}
10778
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010779static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010780AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010781{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010782 ushort wval;
10783 ushort sum;
10784 ushort *wbuf;
10785 int cfg_beg;
10786 int cfg_end;
10787 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
10788 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010789
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010790 wbuf = (ushort *)cfg_buf;
10791 sum = 0;
10792 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
10793 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10794 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10795 sum += *wbuf;
10796 }
10797 if (bus_type & ASC_IS_VL) {
10798 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10799 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10800 } else {
10801 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10802 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10803 }
10804 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10805 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
10806 if (s_addr <= uchar_end_in_config) {
10807 /*
10808 * Swap all char fields - must unswap bytes already swapped
10809 * by AscReadEEPWord().
10810 */
10811 *wbuf = le16_to_cpu(wval);
10812 } else {
10813 /* Don't swap word field at the end - cntl field. */
10814 *wbuf = wval;
10815 }
10816 sum += wval; /* Checksum treats all EEPROM data as words. */
10817 }
10818 /*
10819 * Read the checksum word which will be compared against 'sum'
10820 * by the caller. Word field already swapped.
10821 */
10822 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10823 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010824}
10825
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010826static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010827AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010828{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010829 int n_error;
10830 ushort *wbuf;
10831 ushort word;
10832 ushort sum;
10833 int s_addr;
10834 int cfg_beg;
10835 int cfg_end;
10836 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010837
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010838 wbuf = (ushort *)cfg_buf;
10839 n_error = 0;
10840 sum = 0;
10841 /* Write two config words; AscWriteEEPWord() will swap bytes. */
10842 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10843 sum += *wbuf;
10844 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10845 n_error++;
10846 }
10847 }
10848 if (bus_type & ASC_IS_VL) {
10849 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10850 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10851 } else {
10852 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10853 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10854 }
10855 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10856 if (s_addr <= uchar_end_in_config) {
10857 /*
10858 * This is a char field. Swap char fields before they are
10859 * swapped again by AscWriteEEPWord().
10860 */
10861 word = cpu_to_le16(*wbuf);
10862 if (word !=
10863 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
10864 n_error++;
10865 }
10866 } else {
10867 /* Don't swap word field at the end - cntl field. */
10868 if (*wbuf !=
10869 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10870 n_error++;
10871 }
10872 }
10873 sum += *wbuf; /* Checksum calculated from word values. */
10874 }
10875 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
10876 *wbuf = sum;
10877 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
10878 n_error++;
10879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010880
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010881 /* Read EEPROM back again. */
10882 wbuf = (ushort *)cfg_buf;
10883 /*
10884 * Read two config words; Byte-swapping done by AscReadEEPWord().
10885 */
10886 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10887 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
10888 n_error++;
10889 }
10890 }
10891 if (bus_type & ASC_IS_VL) {
10892 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10893 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10894 } else {
10895 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10896 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10897 }
10898 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10899 if (s_addr <= uchar_end_in_config) {
10900 /*
10901 * Swap all char fields. Must unswap bytes already swapped
10902 * by AscReadEEPWord().
10903 */
10904 word =
10905 le16_to_cpu(AscReadEEPWord
10906 (iop_base, (uchar)s_addr));
10907 } else {
10908 /* Don't swap word field at the end - cntl field. */
10909 word = AscReadEEPWord(iop_base, (uchar)s_addr);
10910 }
10911 if (*wbuf != word) {
10912 n_error++;
10913 }
10914 }
10915 /* Read checksum; Byte swapping not needed. */
10916 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
10917 n_error++;
10918 }
10919 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010920}
10921
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010922static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010923AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010924{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010925 int retry;
10926 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010927
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010928 retry = 0;
10929 while (TRUE) {
10930 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
10931 bus_type)) == 0) {
10932 break;
10933 }
10934 if (++retry > ASC_EEP_MAX_RETRY) {
10935 break;
10936 }
10937 }
10938 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010939}
10940
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010941static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010942{
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010943 char type = sdev->type;
10944 ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010945
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010946 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
10947 if (!(asc_dvc->init_sdtr & tid_bits)) {
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010948 if ((type == TYPE_ROM) &&
10949 (strncmp(sdev->vendor, "HP ", 3) == 0)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010950 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
10951 }
10952 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010953 if ((type == TYPE_PROCESSOR) ||
10954 (type == TYPE_SCANNER) || (type == TYPE_ROM) ||
10955 (type == TYPE_TAPE)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010956 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
10957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010958
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010959 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
10960 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010961 sdev->id,
10962 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010963 }
10964 }
10965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010966}
10967
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010968static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010969{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010970 uchar byte_data;
10971 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010972
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010973 if (isodd_word(addr)) {
10974 AscSetChipLramAddr(iop_base, addr - 1);
10975 word_data = AscGetChipLramData(iop_base);
10976 byte_data = (uchar)((word_data >> 8) & 0xFF);
10977 } else {
10978 AscSetChipLramAddr(iop_base, addr);
10979 word_data = AscGetChipLramData(iop_base);
10980 byte_data = (uchar)(word_data & 0xFF);
10981 }
10982 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010983}
Linus Torvalds1da177e2005-04-16 15:20:36 -070010984
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010985static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
10986{
10987 ushort word_data;
10988
10989 AscSetChipLramAddr(iop_base, addr);
10990 word_data = AscGetChipLramData(iop_base);
10991 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010992}
10993
10994#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010995static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010996{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010997 ushort val_low, val_high;
10998 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010999
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011000 AscSetChipLramAddr(iop_base, addr);
11001 val_low = AscGetChipLramData(iop_base);
11002 val_high = AscGetChipLramData(iop_base);
11003 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
11004 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011005}
11006#endif /* CC_VERY_LONG_SG_LIST */
11007
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011008static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011009{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011010 AscSetChipLramAddr(iop_base, addr);
11011 AscSetChipLramData(iop_base, word_val);
11012 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011013}
11014
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011015static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011016{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011017 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011018
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011019 if (isodd_word(addr)) {
11020 addr--;
11021 word_data = AscReadLramWord(iop_base, addr);
11022 word_data &= 0x00FF;
11023 word_data |= (((ushort)byte_val << 8) & 0xFF00);
11024 } else {
11025 word_data = AscReadLramWord(iop_base, addr);
11026 word_data &= 0xFF00;
11027 word_data |= ((ushort)byte_val & 0x00FF);
11028 }
11029 AscWriteLramWord(iop_base, addr, word_data);
11030 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011031}
11032
11033/*
11034 * Copy 2 bytes to LRAM.
11035 *
11036 * The source data is assumed to be in little-endian order in memory
11037 * and is maintained in little-endian order when written to LRAM.
11038 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011039static void
11040AscMemWordCopyPtrToLram(PortAddr iop_base,
11041 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011042{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011043 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011044
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011045 AscSetChipLramAddr(iop_base, s_addr);
11046 for (i = 0; i < 2 * words; i += 2) {
11047 /*
11048 * On a little-endian system the second argument below
11049 * produces a little-endian ushort which is written to
11050 * LRAM in little-endian order. On a big-endian system
11051 * the second argument produces a big-endian ushort which
11052 * is "transparently" byte-swapped by outpw() and written
11053 * in little-endian order to LRAM.
11054 */
11055 outpw(iop_base + IOP_RAM_DATA,
11056 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
11057 }
11058 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011059}
11060
11061/*
11062 * Copy 4 bytes to LRAM.
11063 *
11064 * The source data is assumed to be in little-endian order in memory
11065 * and is maintained in little-endian order when writen to LRAM.
11066 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011067static void
11068AscMemDWordCopyPtrToLram(PortAddr iop_base,
11069 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011070{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011071 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011072
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011073 AscSetChipLramAddr(iop_base, s_addr);
11074 for (i = 0; i < 4 * dwords; i += 4) {
11075 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11076 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11077 }
11078 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011079}
11080
11081/*
11082 * Copy 2 bytes from LRAM.
11083 *
11084 * The source data is assumed to be in little-endian order in LRAM
11085 * and is maintained in little-endian order when written to memory.
11086 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011087static void
11088AscMemWordCopyPtrFromLram(PortAddr iop_base,
11089 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011090{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011091 int i;
11092 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011094 AscSetChipLramAddr(iop_base, s_addr);
11095 for (i = 0; i < 2 * words; i += 2) {
11096 word = inpw(iop_base + IOP_RAM_DATA);
11097 d_buffer[i] = word & 0xff;
11098 d_buffer[i + 1] = (word >> 8) & 0xff;
11099 }
11100 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011101}
11102
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011103static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011104{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011105 ASC_DCNT sum;
11106 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011107
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011108 sum = 0L;
11109 for (i = 0; i < words; i++, s_addr += 2) {
11110 sum += AscReadLramWord(iop_base, s_addr);
11111 }
11112 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011113}
11114
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011115static void
11116AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011117{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011118 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011119
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011120 AscSetChipLramAddr(iop_base, s_addr);
11121 for (i = 0; i < words; i++) {
11122 AscSetChipLramData(iop_base, set_wval);
11123 }
11124 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011125}
11126
Linus Torvalds1da177e2005-04-16 15:20:36 -070011127/*
11128 * --- Adv Library Functions
11129 */
11130
11131/* a_mcode.h */
11132
11133/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011134static unsigned char _adv_asc3550_buf[] = {
11135 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11136 0x01, 0x00, 0x48, 0xe4,
11137 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11138 0x28, 0x0e, 0x9e, 0xe7,
11139 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11140 0x55, 0xf0, 0x01, 0xf6,
11141 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11142 0x00, 0xec, 0x85, 0xf0,
11143 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11144 0x86, 0xf0, 0xb4, 0x00,
11145 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11146 0xaa, 0x18, 0x02, 0x80,
11147 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11148 0x00, 0x57, 0x01, 0xea,
11149 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11150 0x03, 0xe6, 0xb6, 0x00,
11151 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11152 0x02, 0x4a, 0xb9, 0x54,
11153 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11154 0x3e, 0x00, 0x80, 0x00,
11155 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11156 0x74, 0x01, 0x76, 0x01,
11157 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11158 0x4c, 0x1c, 0xbb, 0x55,
11159 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11160 0x03, 0xf7, 0x06, 0xf7,
11161 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11162 0x30, 0x13, 0x64, 0x15,
11163 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11164 0x04, 0xea, 0x5d, 0xf0,
11165 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11166 0xcc, 0x00, 0x20, 0x01,
11167 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11168 0x40, 0x13, 0x30, 0x1c,
11169 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11170 0x59, 0xf0, 0xa7, 0xf0,
11171 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11172 0xa4, 0x00, 0xb5, 0x00,
11173 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11174 0x14, 0x0e, 0x02, 0x10,
11175 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11176 0x10, 0x15, 0x14, 0x15,
11177 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11178 0x91, 0x44, 0x0a, 0x45,
11179 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11180 0x83, 0x59, 0x05, 0xe6,
11181 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11182 0x02, 0xfa, 0x03, 0xfa,
11183 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11184 0x9e, 0x00, 0xa8, 0x00,
11185 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11186 0x7a, 0x01, 0xc0, 0x01,
11187 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11188 0x69, 0x08, 0xba, 0x08,
11189 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11190 0xf1, 0x10, 0x06, 0x12,
11191 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11192 0x8a, 0x15, 0xc6, 0x17,
11193 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11194 0x0e, 0x47, 0x48, 0x47,
11195 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11196 0x14, 0x56, 0x77, 0x57,
11197 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11198 0xf0, 0x29, 0x02, 0xfe,
11199 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11200 0xfe, 0x80, 0x01, 0xff,
11201 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11202 0x00, 0xfe, 0x57, 0x24,
11203 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11204 0x00, 0x00, 0xff, 0x08,
11205 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11206 0xff, 0xff, 0xff, 0x0f,
11207 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11208 0xfe, 0x04, 0xf7, 0xcf,
11209 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11210 0x0b, 0x3c, 0x2a, 0xfe,
11211 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11212 0xfe, 0xf0, 0x01, 0xfe,
11213 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11214 0x02, 0xfe, 0xd4, 0x0c,
11215 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11216 0x1c, 0x05, 0xfe, 0xa6,
11217 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11218 0xf0, 0xfe, 0x86, 0x02,
11219 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11220 0xfe, 0x46, 0xf0, 0xfe,
11221 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11222 0x44, 0x02, 0xfe, 0x44,
11223 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11224 0xa0, 0x17, 0x06, 0x18,
11225 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11226 0x1e, 0x1c, 0xfe, 0xe9,
11227 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11228 0x0a, 0x6b, 0x01, 0x9e,
11229 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11230 0x01, 0x82, 0xfe, 0xbd,
11231 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11232 0x58, 0x1c, 0x17, 0x06,
11233 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11234 0xfe, 0x94, 0x02, 0xfe,
11235 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11236 0x01, 0xfe, 0x54, 0x0f,
11237 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11238 0x69, 0x10, 0x17, 0x06,
11239 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11240 0xf6, 0xc7, 0x01, 0xfe,
11241 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11242 0x02, 0x29, 0x0a, 0x40,
11243 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11244 0x58, 0x0a, 0x99, 0x01,
11245 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11246 0x2a, 0x46, 0xfe, 0x02,
11247 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11248 0x01, 0xfe, 0x07, 0x4b,
11249 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11250 0xfe, 0x56, 0x03, 0xfe,
11251 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11252 0xfe, 0x9f, 0xf0, 0xfe,
11253 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11254 0x1c, 0xeb, 0x09, 0x04,
11255 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11256 0x01, 0x0e, 0xac, 0x75,
11257 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11258 0xfe, 0x82, 0xf0, 0xfe,
11259 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11260 0x32, 0x1f, 0xfe, 0xb4,
11261 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11262 0x0a, 0xf0, 0xfe, 0x7a,
11263 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11264 0x01, 0x33, 0x8f, 0xfe,
11265 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11266 0xf7, 0xfe, 0x48, 0x1c,
11267 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11268 0x0a, 0xca, 0x01, 0x0e,
11269 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11270 0x2c, 0x01, 0x33, 0x8f,
11271 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11272 0xfe, 0x3c, 0x04, 0x1f,
11273 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11274 0x12, 0x2b, 0xff, 0x02,
11275 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11276 0x22, 0x30, 0x2e, 0xd5,
11277 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11278 0xfe, 0x4c, 0x54, 0x64,
11279 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11280 0xfe, 0x2a, 0x13, 0x2f,
11281 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11282 0xd3, 0xfa, 0xef, 0x86,
11283 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11284 0x1d, 0xfe, 0x1c, 0x12,
11285 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11286 0x70, 0x0c, 0x02, 0x22,
11287 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11288 0x01, 0x33, 0x02, 0x29,
11289 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11290 0x80, 0xfe, 0x31, 0xe4,
11291 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11292 0xfe, 0x70, 0x12, 0x49,
11293 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11294 0x80, 0x05, 0xfe, 0x31,
11295 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11296 0x28, 0xfe, 0x42, 0x12,
11297 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11298 0x11, 0xfe, 0xe3, 0x00,
11299 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11300 0x64, 0x05, 0x83, 0x24,
11301 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11302 0x09, 0x48, 0x01, 0x08,
11303 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11304 0x86, 0x24, 0x06, 0x12,
11305 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11306 0x01, 0xa7, 0x14, 0x92,
11307 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11308 0x02, 0x22, 0x05, 0xfe,
11309 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11310 0x47, 0x01, 0xa7, 0x26,
11311 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11312 0x01, 0xfe, 0xaa, 0x14,
11313 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11314 0x05, 0x50, 0xb4, 0x0c,
11315 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11316 0x13, 0x01, 0xfe, 0x14,
11317 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11318 0xff, 0x02, 0x00, 0x57,
11319 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11320 0x72, 0x06, 0x49, 0x04,
11321 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11322 0x06, 0x11, 0x9a, 0x01,
11323 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11324 0x01, 0xa7, 0xec, 0x72,
11325 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11326 0xfe, 0x0a, 0xf0, 0xfe,
11327 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11328 0x8d, 0x81, 0x02, 0x22,
11329 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11330 0x01, 0x08, 0x15, 0x00,
11331 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11332 0x00, 0x02, 0xfe, 0x32,
11333 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11334 0xfe, 0x1b, 0x00, 0x01,
11335 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11336 0x08, 0x15, 0x06, 0x01,
11337 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11338 0x9a, 0x81, 0x4b, 0x1d,
11339 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11340 0x45, 0xfe, 0x32, 0x12,
11341 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11342 0xfe, 0x32, 0x07, 0x8d,
11343 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11344 0x06, 0x15, 0x19, 0x02,
11345 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11346 0x90, 0x77, 0xfe, 0xca,
11347 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11348 0x10, 0xfe, 0x0e, 0x12,
11349 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11350 0x83, 0xe7, 0xc4, 0xa1,
11351 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11352 0x40, 0x12, 0x58, 0x01,
11353 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11354 0x51, 0x83, 0xfb, 0xfe,
11355 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11356 0xfe, 0x40, 0x50, 0xfe,
11357 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11358 0xfe, 0x2a, 0x12, 0xfe,
11359 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11360 0x85, 0x01, 0xa8, 0xfe,
11361 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11362 0x18, 0x57, 0xfb, 0xfe,
11363 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11364 0x0c, 0x39, 0x18, 0x3a,
11365 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11366 0x11, 0x65, 0xfe, 0x48,
11367 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11368 0xdd, 0xb8, 0xfe, 0x80,
11369 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11370 0xfe, 0x7a, 0x08, 0x8d,
11371 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11372 0x10, 0x61, 0x04, 0x06,
11373 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11374 0x12, 0xfe, 0x2e, 0x1c,
11375 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11376 0x52, 0x12, 0xfe, 0x2c,
11377 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11378 0x08, 0xfe, 0x8a, 0x10,
11379 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11380 0x24, 0x0a, 0xab, 0xfe,
11381 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11382 0x1c, 0x12, 0xb5, 0xfe,
11383 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11384 0x1c, 0x06, 0x16, 0x9d,
11385 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11386 0x14, 0x92, 0x01, 0x33,
11387 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11388 0xfe, 0x74, 0x18, 0x1c,
11389 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11390 0x01, 0xe6, 0x1e, 0x27,
11391 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11392 0x09, 0x04, 0x6a, 0xfe,
11393 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11394 0xfe, 0x83, 0x80, 0xfe,
11395 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11396 0x27, 0xfe, 0x40, 0x59,
11397 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11398 0x7c, 0xbe, 0x54, 0xbf,
11399 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11400 0x79, 0x56, 0x68, 0x57,
11401 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11402 0xa2, 0x23, 0x0c, 0x7b,
11403 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11404 0x16, 0xd7, 0x79, 0x39,
11405 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11406 0xfe, 0x10, 0x58, 0xfe,
11407 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
11408 0x19, 0x16, 0xd7, 0x09,
11409 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
11410 0xfe, 0x10, 0x90, 0xfe,
11411 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
11412 0x11, 0x9b, 0x09, 0x04,
11413 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
11414 0xfe, 0x0c, 0x58, 0xfe,
11415 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
11416 0x0b, 0xfe, 0x1a, 0x12,
11417 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
11418 0x14, 0x7a, 0x01, 0x33,
11419 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
11420 0xfe, 0xed, 0x19, 0xbf,
11421 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
11422 0x34, 0xfe, 0x74, 0x10,
11423 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
11424 0x84, 0x05, 0xcb, 0x1c,
11425 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
11426 0xf0, 0xfe, 0xc4, 0x0a,
11427 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
11428 0xce, 0xf0, 0xfe, 0xca,
11429 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
11430 0x22, 0x00, 0x02, 0x5a,
11431 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
11432 0xfe, 0xd0, 0xf0, 0xfe,
11433 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
11434 0x4c, 0xfe, 0x10, 0x10,
11435 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
11436 0x2a, 0x13, 0xfe, 0x4e,
11437 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
11438 0x16, 0x32, 0x2a, 0x73,
11439 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
11440 0x32, 0x8c, 0xfe, 0x48,
11441 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
11442 0xdb, 0x10, 0x11, 0xfe,
11443 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
11444 0x22, 0x30, 0x2e, 0xd8,
11445 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
11446 0x45, 0x0f, 0xfe, 0x42,
11447 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
11448 0x09, 0x04, 0x0b, 0xfe,
11449 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
11450 0x00, 0x21, 0xfe, 0xa6,
11451 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
11452 0xfe, 0xe2, 0x10, 0x01,
11453 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
11454 0x01, 0x6f, 0x02, 0x29,
11455 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
11456 0x01, 0x86, 0x3e, 0x0b,
11457 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
11458 0x3e, 0x0b, 0x0f, 0xfe,
11459 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
11460 0xe8, 0x59, 0x11, 0x2d,
11461 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
11462 0x04, 0x0b, 0x84, 0x3e,
11463 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
11464 0x09, 0x04, 0x1b, 0xfe,
11465 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
11466 0x1c, 0x1c, 0xfe, 0x9d,
11467 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
11468 0xfe, 0x15, 0x00, 0xfe,
11469 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
11470 0x0f, 0xfe, 0x47, 0x00,
11471 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
11472 0xab, 0x70, 0x05, 0x6b,
11473 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
11474 0x1c, 0x42, 0x59, 0x01,
11475 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
11476 0x00, 0x37, 0x97, 0x01,
11477 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
11478 0x1d, 0xfe, 0xce, 0x45,
11479 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
11480 0x57, 0x05, 0x51, 0xfe,
11481 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
11482 0x46, 0x09, 0x04, 0x1d,
11483 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
11484 0x99, 0x01, 0x0e, 0xfe,
11485 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
11486 0xfe, 0xee, 0x14, 0xee,
11487 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
11488 0x13, 0x02, 0x29, 0x1e,
11489 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
11490 0xce, 0x1e, 0x2d, 0x47,
11491 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
11492 0x12, 0x4d, 0x01, 0xfe,
11493 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
11494 0xf0, 0x0d, 0xfe, 0x02,
11495 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
11496 0xf6, 0xfe, 0x34, 0x01,
11497 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
11498 0xaf, 0xfe, 0x02, 0xea,
11499 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
11500 0x05, 0xfe, 0x38, 0x01,
11501 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
11502 0x0c, 0xfe, 0x62, 0x01,
11503 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
11504 0x03, 0x23, 0x03, 0x1e,
11505 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
11506 0x71, 0x13, 0xfe, 0x24,
11507 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
11508 0xdc, 0xfe, 0x73, 0x57,
11509 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
11510 0x80, 0x5d, 0x03, 0xfe,
11511 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
11512 0x75, 0x03, 0x09, 0x04,
11513 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
11514 0xfe, 0x1e, 0x80, 0xe1,
11515 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
11516 0x90, 0xa3, 0xfe, 0x3c,
11517 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
11518 0x16, 0x2f, 0x07, 0x2d,
11519 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
11520 0xe8, 0x11, 0xfe, 0xe9,
11521 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
11522 0x1e, 0x1c, 0xfe, 0x14,
11523 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
11524 0x09, 0x04, 0x4f, 0xfe,
11525 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
11526 0x40, 0x12, 0x20, 0x63,
11527 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
11528 0x1c, 0x05, 0xfe, 0xac,
11529 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
11530 0xfe, 0xb0, 0x00, 0xfe,
11531 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
11532 0x24, 0x69, 0x12, 0xc9,
11533 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
11534 0x90, 0x4d, 0xfe, 0x91,
11535 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
11536 0xfe, 0x90, 0x4d, 0xfe,
11537 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
11538 0x46, 0x1e, 0x20, 0xed,
11539 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
11540 0x70, 0xfe, 0x14, 0x1c,
11541 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
11542 0xfe, 0x07, 0xe6, 0x1d,
11543 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
11544 0xfa, 0xef, 0xfe, 0x42,
11545 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
11546 0xfe, 0x36, 0x12, 0xf0,
11547 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
11548 0x3d, 0x75, 0x07, 0x10,
11549 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
11550 0x10, 0x07, 0x7e, 0x45,
11551 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
11552 0xfe, 0x01, 0xec, 0x97,
11553 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
11554 0x27, 0x01, 0xda, 0xfe,
11555 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
11556 0xfe, 0x48, 0x12, 0x07,
11557 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
11558 0xfe, 0x3e, 0x11, 0x07,
11559 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
11560 0x11, 0x07, 0x19, 0xfe,
11561 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
11562 0x01, 0x08, 0x8c, 0x43,
11563 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
11564 0x7e, 0x02, 0x29, 0x2b,
11565 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
11566 0xfc, 0x10, 0x09, 0x04,
11567 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
11568 0xc6, 0x10, 0x1e, 0x58,
11569 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
11570 0x54, 0x18, 0x55, 0x23,
11571 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
11572 0xa5, 0xc0, 0x38, 0xc1,
11573 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
11574 0x05, 0xfa, 0x4e, 0xfe,
11575 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
11576 0x0c, 0x56, 0x18, 0x57,
11577 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
11578 0x00, 0x56, 0xfe, 0xa1,
11579 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
11580 0x58, 0xfe, 0x1f, 0x40,
11581 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
11582 0x31, 0x57, 0xfe, 0x44,
11583 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
11584 0x8a, 0x50, 0x05, 0x39,
11585 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
11586 0x12, 0xcd, 0x02, 0x5b,
11587 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
11588 0x2f, 0x07, 0x9b, 0x21,
11589 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
11590 0x39, 0x68, 0x3a, 0xfe,
11591 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
11592 0x51, 0xfe, 0x8e, 0x51,
11593 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
11594 0x01, 0x08, 0x25, 0x32,
11595 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
11596 0x3b, 0x02, 0x44, 0x01,
11597 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
11598 0x01, 0x08, 0x1f, 0xa2,
11599 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
11600 0x00, 0x28, 0x84, 0x49,
11601 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
11602 0x78, 0x3d, 0xfe, 0xda,
11603 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
11604 0x05, 0xc6, 0x28, 0x84,
11605 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
11606 0x14, 0xfe, 0x03, 0x17,
11607 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
11608 0xfe, 0xaa, 0x14, 0x02,
11609 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
11610 0x21, 0x44, 0x01, 0xfe,
11611 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
11612 0xfe, 0x4a, 0xf4, 0x0b,
11613 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
11614 0x85, 0x02, 0x5b, 0x05,
11615 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
11616 0xd8, 0x14, 0x02, 0x5c,
11617 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
11618 0x01, 0x08, 0x23, 0x72,
11619 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
11620 0x12, 0x5e, 0x2b, 0x01,
11621 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
11622 0x1c, 0xfe, 0xff, 0x7f,
11623 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
11624 0x57, 0x48, 0x8b, 0x1c,
11625 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
11626 0x00, 0x57, 0x48, 0x8b,
11627 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
11628 0x03, 0x0a, 0x50, 0x01,
11629 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
11630 0x54, 0xfe, 0x00, 0xf4,
11631 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
11632 0x03, 0x7c, 0x63, 0x27,
11633 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
11634 0xfe, 0x82, 0x4a, 0xfe,
11635 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
11636 0x42, 0x48, 0x5f, 0x60,
11637 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
11638 0x1f, 0xfe, 0xa2, 0x14,
11639 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
11640 0xcc, 0x12, 0x49, 0x04,
11641 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
11642 0xe8, 0x13, 0x3b, 0x13,
11643 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
11644 0xa1, 0xff, 0x02, 0x83,
11645 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
11646 0x13, 0x06, 0xfe, 0x56,
11647 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
11648 0x64, 0x00, 0x17, 0x93,
11649 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
11650 0xc8, 0x00, 0x8e, 0xe4,
11651 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
11652 0x01, 0xba, 0xfe, 0x4e,
11653 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
11654 0xfe, 0x60, 0x14, 0xfe,
11655 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
11656 0xfe, 0x22, 0x13, 0x1c,
11657 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
11658 0xfe, 0x9c, 0x14, 0xb7,
11659 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
11660 0xfe, 0x9c, 0x14, 0xb7,
11661 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
11662 0xfe, 0xb4, 0x56, 0xfe,
11663 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
11664 0xe5, 0x15, 0x0b, 0x01,
11665 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
11666 0x49, 0x01, 0x08, 0x03,
11667 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
11668 0x15, 0x06, 0x01, 0x08,
11669 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
11670 0x4a, 0x01, 0x08, 0x03,
11671 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
11672 0xfe, 0x49, 0xf4, 0x00,
11673 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
11674 0x08, 0x2f, 0x07, 0xfe,
11675 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
11676 0x01, 0x43, 0x1e, 0xcd,
11677 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11678 0xed, 0x88, 0x07, 0x10,
11679 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
11680 0x80, 0x01, 0x0e, 0x88,
11681 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
11682 0x88, 0x03, 0x0a, 0x42,
11683 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11684 0xfe, 0x80, 0x80, 0xf2,
11685 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
11686 0x01, 0x82, 0x03, 0x17,
11687 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
11688 0xfe, 0x24, 0x1c, 0xfe,
11689 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
11690 0x91, 0x1d, 0x66, 0xfe,
11691 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
11692 0xda, 0x10, 0x17, 0x10,
11693 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
11694 0x05, 0xfe, 0x66, 0x01,
11695 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
11696 0xfe, 0x3c, 0x50, 0x66,
11697 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
11698 0x40, 0x16, 0xfe, 0xb6,
11699 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
11700 0x10, 0x71, 0xfe, 0x83,
11701 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
11702 0xfe, 0x62, 0x16, 0xfe,
11703 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
11704 0xfe, 0x98, 0xe7, 0x00,
11705 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
11706 0xfe, 0x30, 0xbc, 0xfe,
11707 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
11708 0xc5, 0x90, 0xfe, 0x9a,
11709 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
11710 0x42, 0x10, 0xfe, 0x02,
11711 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
11712 0xfe, 0x1d, 0xf7, 0x4f,
11713 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
11714 0x47, 0xfe, 0x83, 0x58,
11715 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
11716 0xfe, 0xdd, 0x00, 0x63,
11717 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
11718 0x06, 0x37, 0x95, 0xa9,
11719 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
11720 0x18, 0x1c, 0x1a, 0x5d,
11721 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
11722 0xe1, 0x10, 0x78, 0x2c,
11723 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
11724 0x13, 0x3c, 0x8a, 0x0a,
11725 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
11726 0xe3, 0xfe, 0x00, 0xcc,
11727 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
11728 0x0e, 0xf2, 0x01, 0x6f,
11729 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
11730 0xf6, 0xfe, 0xd6, 0xf0,
11731 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
11732 0x15, 0x00, 0x59, 0x76,
11733 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
11734 0x11, 0x2d, 0x01, 0x6f,
11735 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
11736 0xc8, 0xfe, 0x48, 0x55,
11737 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
11738 0x99, 0x01, 0x0e, 0xf0,
11739 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
11740 0x75, 0x03, 0x0a, 0x42,
11741 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
11742 0x0e, 0x73, 0x75, 0x03,
11743 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
11744 0xfe, 0x3a, 0x45, 0x5b,
11745 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
11746 0xfe, 0x02, 0xe6, 0x1b,
11747 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
11748 0xfe, 0x94, 0x00, 0xfe,
11749 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
11750 0xe6, 0x2c, 0xfe, 0x4e,
11751 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
11752 0x03, 0x07, 0x7a, 0xfe,
11753 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
11754 0x07, 0x1b, 0xfe, 0x5a,
11755 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
11756 0x24, 0x2c, 0xdc, 0x07,
11757 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
11758 0x9f, 0xad, 0x03, 0x14,
11759 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
11760 0x03, 0x25, 0xfe, 0xca,
11761 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
11762 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011763};
11764
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011765static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
11766static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011767
11768/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011769static unsigned char _adv_asc38C0800_buf[] = {
11770 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
11771 0x01, 0x00, 0x48, 0xe4,
11772 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
11773 0x1c, 0x0f, 0x00, 0xf6,
11774 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
11775 0x09, 0xe7, 0x55, 0xf0,
11776 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
11777 0x18, 0xf4, 0x08, 0x00,
11778 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
11779 0x86, 0xf0, 0xb1, 0xf0,
11780 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
11781 0x3c, 0x00, 0xbb, 0x00,
11782 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
11783 0xba, 0x13, 0x18, 0x40,
11784 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
11785 0x6e, 0x01, 0x74, 0x01,
11786 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
11787 0xc0, 0x00, 0x01, 0x01,
11788 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
11789 0x08, 0x12, 0x02, 0x4a,
11790 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
11791 0x5d, 0xf0, 0x02, 0xfa,
11792 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
11793 0x68, 0x01, 0x6a, 0x01,
11794 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
11795 0x06, 0x13, 0x4c, 0x1c,
11796 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
11797 0x0f, 0x00, 0x47, 0x00,
11798 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
11799 0x4e, 0x1c, 0x10, 0x44,
11800 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
11801 0x05, 0x00, 0x34, 0x00,
11802 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
11803 0x42, 0x0c, 0x12, 0x0f,
11804 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
11805 0x00, 0x4e, 0x42, 0x54,
11806 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11807 0x59, 0xf0, 0xb8, 0xf0,
11808 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
11809 0x19, 0x00, 0x33, 0x00,
11810 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
11811 0xe7, 0x00, 0xe2, 0x03,
11812 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
11813 0x12, 0x13, 0x24, 0x14,
11814 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
11815 0x36, 0x1c, 0x08, 0x44,
11816 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
11817 0x3a, 0x55, 0x83, 0x55,
11818 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
11819 0x0c, 0xf0, 0x04, 0xf8,
11820 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
11821 0xa8, 0x00, 0xaa, 0x00,
11822 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
11823 0xc4, 0x01, 0xc6, 0x01,
11824 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
11825 0x68, 0x08, 0x69, 0x08,
11826 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
11827 0xed, 0x10, 0xf1, 0x10,
11828 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
11829 0x1e, 0x13, 0x46, 0x14,
11830 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
11831 0xca, 0x18, 0xe6, 0x19,
11832 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
11833 0xf0, 0x2b, 0x02, 0xfe,
11834 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
11835 0xfe, 0x84, 0x01, 0xff,
11836 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11837 0x00, 0xfe, 0x57, 0x24,
11838 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
11839 0x00, 0x00, 0xff, 0x08,
11840 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11841 0xff, 0xff, 0xff, 0x11,
11842 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11843 0xfe, 0x04, 0xf7, 0xd6,
11844 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
11845 0x0a, 0x42, 0x2c, 0xfe,
11846 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
11847 0xfe, 0xf4, 0x01, 0xfe,
11848 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
11849 0x02, 0xfe, 0xc8, 0x0d,
11850 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11851 0x1c, 0x03, 0xfe, 0xa6,
11852 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
11853 0xf0, 0xfe, 0x8a, 0x02,
11854 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
11855 0xfe, 0x46, 0xf0, 0xfe,
11856 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11857 0x48, 0x02, 0xfe, 0x44,
11858 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
11859 0xaa, 0x18, 0x06, 0x14,
11860 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
11861 0x1e, 0x1c, 0xfe, 0xe9,
11862 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
11863 0x09, 0x70, 0x01, 0xa8,
11864 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
11865 0x01, 0x87, 0xfe, 0xbd,
11866 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11867 0x58, 0x1c, 0x18, 0x06,
11868 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
11869 0xfe, 0x98, 0x02, 0xfe,
11870 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
11871 0x01, 0xfe, 0x48, 0x10,
11872 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
11873 0x69, 0x10, 0x18, 0x06,
11874 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
11875 0xf6, 0xce, 0x01, 0xfe,
11876 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
11877 0x82, 0x16, 0x02, 0x2b,
11878 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
11879 0xfe, 0x41, 0x58, 0x09,
11880 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
11881 0x82, 0x16, 0x02, 0x2b,
11882 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
11883 0xfe, 0x77, 0x57, 0xfe,
11884 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
11885 0xfe, 0x40, 0x1c, 0x1c,
11886 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
11887 0x03, 0xfe, 0x11, 0xf0,
11888 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
11889 0xfe, 0x11, 0x00, 0x02,
11890 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
11891 0x21, 0x22, 0xa3, 0xb7,
11892 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
11893 0x12, 0xd1, 0x1c, 0xd9,
11894 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
11895 0xfe, 0xe4, 0x00, 0x27,
11896 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
11897 0x06, 0xf0, 0xfe, 0xc8,
11898 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
11899 0x70, 0x28, 0x17, 0xfe,
11900 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
11901 0xf9, 0x2c, 0x99, 0x19,
11902 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
11903 0x74, 0x01, 0xaf, 0x8c,
11904 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
11905 0x8d, 0x51, 0x64, 0x79,
11906 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
11907 0xfe, 0x6a, 0x02, 0x02,
11908 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
11909 0xfe, 0x3c, 0x04, 0x3b,
11910 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
11911 0x00, 0x10, 0x01, 0x0b,
11912 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
11913 0xfe, 0x4c, 0x44, 0xfe,
11914 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
11915 0xda, 0x4f, 0x79, 0x2a,
11916 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
11917 0xfe, 0x2a, 0x13, 0x32,
11918 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
11919 0x54, 0x6b, 0xda, 0xfe,
11920 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
11921 0x08, 0x13, 0x32, 0x07,
11922 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
11923 0x08, 0x05, 0x06, 0x4d,
11924 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
11925 0x2d, 0x12, 0xfe, 0xe6,
11926 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
11927 0x02, 0x2b, 0xfe, 0x42,
11928 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
11929 0xfe, 0x87, 0x80, 0xfe,
11930 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
11931 0x07, 0x19, 0xfe, 0x7c,
11932 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
11933 0x17, 0xfe, 0x90, 0x05,
11934 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
11935 0xa0, 0x00, 0x28, 0xfe,
11936 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
11937 0x34, 0xfe, 0x89, 0x48,
11938 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
11939 0x12, 0xfe, 0xe3, 0x00,
11940 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11941 0x70, 0x05, 0x88, 0x25,
11942 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
11943 0x09, 0x48, 0xff, 0x02,
11944 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
11945 0x08, 0x53, 0x05, 0xcb,
11946 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
11947 0x05, 0x1b, 0xfe, 0x22,
11948 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
11949 0x0d, 0x00, 0x01, 0x36,
11950 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
11951 0x03, 0x5c, 0x28, 0xfe,
11952 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
11953 0x05, 0x1f, 0xfe, 0x02,
11954 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
11955 0x01, 0x4b, 0x12, 0xfe,
11956 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
11957 0x12, 0x03, 0x45, 0x28,
11958 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
11959 0x43, 0x48, 0xc4, 0xcc,
11960 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
11961 0x6e, 0x41, 0x01, 0xb2,
11962 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
11963 0xfe, 0xcc, 0x15, 0x1d,
11964 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
11965 0x45, 0xc1, 0x0c, 0x45,
11966 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
11967 0xe2, 0x00, 0x27, 0xdb,
11968 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
11969 0xfe, 0x06, 0xf0, 0xfe,
11970 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
11971 0x16, 0x19, 0x01, 0x0b,
11972 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
11973 0xfe, 0x99, 0xa4, 0x01,
11974 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
11975 0x12, 0x08, 0x05, 0x1a,
11976 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
11977 0x0b, 0x16, 0x00, 0x01,
11978 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
11979 0xe2, 0x6c, 0x58, 0xbe,
11980 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
11981 0xfe, 0x09, 0x6f, 0xba,
11982 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
11983 0xfe, 0x54, 0x07, 0x1c,
11984 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
11985 0x07, 0x02, 0x24, 0x01,
11986 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
11987 0x2c, 0x90, 0xfe, 0xae,
11988 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
11989 0x37, 0x22, 0x20, 0x07,
11990 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
11991 0xfe, 0x06, 0x10, 0xfe,
11992 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
11993 0x37, 0x01, 0xb3, 0xb8,
11994 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
11995 0x50, 0xfe, 0x44, 0x51,
11996 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
11997 0x14, 0x5f, 0xfe, 0x0c,
11998 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
11999 0x14, 0x3e, 0xfe, 0x4a,
12000 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
12001 0x90, 0x0c, 0x60, 0x14,
12002 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
12003 0xfe, 0x44, 0x90, 0xfe,
12004 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
12005 0x0c, 0x5e, 0x14, 0x5f,
12006 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
12007 0x14, 0x3c, 0x21, 0x0c,
12008 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
12009 0x27, 0xdd, 0xfe, 0x9e,
12010 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
12011 0x9a, 0x08, 0xc6, 0xfe,
12012 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
12013 0x95, 0x86, 0x02, 0x24,
12014 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
12015 0x06, 0xfe, 0x10, 0x12,
12016 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
12017 0x1c, 0x02, 0xfe, 0x18,
12018 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
12019 0x2c, 0x1c, 0xfe, 0xaa,
12020 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
12021 0xde, 0x09, 0xfe, 0xb7,
12022 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
12023 0xfe, 0xf1, 0x18, 0xfe,
12024 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
12025 0x14, 0x59, 0xfe, 0x95,
12026 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
12027 0xfe, 0xf0, 0x08, 0xb5,
12028 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
12029 0x0b, 0xb6, 0xfe, 0xbf,
12030 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
12031 0x12, 0xc2, 0xfe, 0xd2,
12032 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
12033 0x06, 0x17, 0x85, 0xc5,
12034 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
12035 0x9d, 0x01, 0x36, 0x10,
12036 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
12037 0x98, 0x80, 0xfe, 0x19,
12038 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
12039 0xfe, 0x44, 0x54, 0xbe,
12040 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
12041 0x02, 0x4a, 0x08, 0x05,
12042 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
12043 0x9c, 0x3c, 0xfe, 0x6c,
12044 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
12045 0x3b, 0x40, 0x03, 0x49,
12046 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
12047 0x8f, 0xfe, 0xe3, 0x54,
12048 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
12049 0xda, 0x09, 0xfe, 0x8b,
12050 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
12051 0x0a, 0x3a, 0x49, 0x3b,
12052 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
12053 0xad, 0xfe, 0x01, 0x59,
12054 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
12055 0x49, 0x8f, 0xfe, 0xe3,
12056 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
12057 0x4a, 0x3a, 0x49, 0x3b,
12058 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
12059 0x02, 0x4a, 0x08, 0x05,
12060 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
12061 0xb7, 0xfe, 0x03, 0xa1,
12062 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12063 0xfe, 0x86, 0x91, 0x6a,
12064 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12065 0x61, 0x0c, 0x7f, 0x14,
12066 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12067 0x9b, 0x2e, 0x9c, 0x3c,
12068 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12069 0xfa, 0x3c, 0x01, 0xef,
12070 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12071 0xe4, 0x08, 0x05, 0x1f,
12072 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12073 0x03, 0x5e, 0x29, 0x5f,
12074 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12075 0xf4, 0x09, 0x08, 0x05,
12076 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12077 0x81, 0x50, 0xfe, 0x10,
12078 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12079 0x08, 0x09, 0x12, 0xa6,
12080 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12081 0x08, 0x09, 0xfe, 0x0c,
12082 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12083 0x08, 0x05, 0x0a, 0xfe,
12084 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12085 0xf0, 0xe2, 0x15, 0x7e,
12086 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12087 0x57, 0x3d, 0xfe, 0xed,
12088 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12089 0x00, 0xff, 0x35, 0xfe,
12090 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12091 0x1e, 0x19, 0x8a, 0x03,
12092 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12093 0xfe, 0xd1, 0xf0, 0xfe,
12094 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12095 0x10, 0xfe, 0xce, 0xf0,
12096 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12097 0x10, 0xfe, 0x22, 0x00,
12098 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12099 0x02, 0x65, 0xfe, 0xd0,
12100 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12101 0x0b, 0x10, 0x58, 0xfe,
12102 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12103 0x12, 0x00, 0x2c, 0x0f,
12104 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12105 0x0c, 0xbc, 0x17, 0x34,
12106 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12107 0x0c, 0x1c, 0x34, 0x94,
12108 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12109 0x4b, 0xfe, 0xdb, 0x10,
12110 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12111 0x89, 0xf0, 0x24, 0x33,
12112 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12113 0x33, 0x31, 0xdf, 0xbc,
12114 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12115 0x17, 0xfe, 0x2c, 0x0d,
12116 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12117 0x12, 0x55, 0xfe, 0x28,
12118 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12119 0x44, 0xfe, 0x28, 0x00,
12120 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12121 0x0f, 0x64, 0x12, 0x2f,
12122 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12123 0x0a, 0xfe, 0xb4, 0x10,
12124 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12125 0xfe, 0x34, 0x46, 0xac,
12126 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12127 0x37, 0x01, 0xf5, 0x01,
12128 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12129 0xfe, 0x2e, 0x03, 0x08,
12130 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12131 0x1a, 0xfe, 0x58, 0x12,
12132 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12133 0xfe, 0x50, 0x0d, 0xfe,
12134 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12135 0xfe, 0xa9, 0x10, 0x10,
12136 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12137 0xfe, 0x13, 0x00, 0xfe,
12138 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12139 0x24, 0x00, 0x8c, 0xb5,
12140 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12141 0xfe, 0x9d, 0x41, 0xfe,
12142 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12143 0xb4, 0x15, 0xfe, 0x31,
12144 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12145 0xec, 0xd0, 0xfc, 0x44,
12146 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12147 0x4b, 0x91, 0xfe, 0x75,
12148 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12149 0x0e, 0xfe, 0x44, 0x48,
12150 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12151 0xfe, 0x41, 0x58, 0x09,
12152 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12153 0x2e, 0x03, 0x09, 0x5d,
12154 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12155 0xce, 0x47, 0xfe, 0xad,
12156 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12157 0x59, 0x13, 0x9f, 0x13,
12158 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12159 0xe0, 0x0e, 0x0f, 0x06,
12160 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12161 0x3a, 0x01, 0x56, 0xfe,
12162 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12163 0x20, 0x4f, 0xfe, 0x05,
12164 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12165 0x48, 0xf4, 0x0d, 0xfe,
12166 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12167 0x15, 0x1a, 0x39, 0xa0,
12168 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12169 0x0c, 0xfe, 0x60, 0x01,
12170 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12171 0x06, 0x13, 0x2f, 0x12,
12172 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12173 0x22, 0x9f, 0xb7, 0x13,
12174 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12175 0xa0, 0xb4, 0xfe, 0xd9,
12176 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12177 0xc3, 0xfe, 0x03, 0xdc,
12178 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12179 0xfe, 0x00, 0xcc, 0x04,
12180 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12181 0xfe, 0x1c, 0x80, 0x07,
12182 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12183 0xfe, 0x0c, 0x90, 0xfe,
12184 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12185 0x0a, 0xfe, 0x3c, 0x50,
12186 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12187 0x16, 0x08, 0x05, 0x1b,
12188 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12189 0xfe, 0x2c, 0x13, 0x01,
12190 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12191 0x0c, 0xfe, 0x64, 0x01,
12192 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12193 0x80, 0x8d, 0xfe, 0x01,
12194 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12195 0x22, 0x20, 0xfb, 0x79,
12196 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12197 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012198
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012199 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12200 0xb2, 0x00, 0xfe, 0x09,
12201 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12202 0x45, 0x0f, 0x46, 0x52,
12203 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12204 0x0f, 0x44, 0x11, 0x0f,
12205 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12206 0x25, 0x11, 0x13, 0x20,
12207 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12208 0x56, 0xfe, 0xd6, 0xf0,
12209 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12210 0x18, 0x1c, 0x04, 0x42,
12211 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12212 0xf5, 0x13, 0x04, 0x01,
12213 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12214 0x13, 0x32, 0x07, 0x2f,
12215 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12216 0x41, 0x48, 0xfe, 0x45,
12217 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12218 0x07, 0x11, 0xac, 0x09,
12219 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12220 0x82, 0x4e, 0xfe, 0x14,
12221 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12222 0xfe, 0x01, 0xec, 0xa2,
12223 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12224 0x2a, 0x01, 0xe3, 0xfe,
12225 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12226 0xfe, 0x48, 0x12, 0x07,
12227 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12228 0xfe, 0x32, 0x12, 0x07,
12229 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12230 0x1f, 0xfe, 0x12, 0x12,
12231 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12232 0x94, 0x4b, 0x04, 0x2d,
12233 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12234 0x32, 0x07, 0xa6, 0xfe,
12235 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12236 0x5a, 0xfe, 0x72, 0x12,
12237 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12238 0xfe, 0x26, 0x13, 0x03,
12239 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12240 0x0c, 0x7f, 0x0c, 0x80,
12241 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12242 0x3c, 0xfe, 0x04, 0x55,
12243 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12244 0x91, 0x10, 0x03, 0x3f,
12245 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12246 0x88, 0x9b, 0x2e, 0x9c,
12247 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12248 0x56, 0x0c, 0x5e, 0x14,
12249 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12250 0x03, 0x60, 0x29, 0x61,
12251 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12252 0x50, 0xfe, 0xc6, 0x50,
12253 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12254 0x29, 0x3e, 0xfe, 0x40,
12255 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12256 0x2d, 0x01, 0x0b, 0x1d,
12257 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12258 0x72, 0x01, 0xaf, 0x1e,
12259 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12260 0x0a, 0x55, 0x35, 0xfe,
12261 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12262 0x02, 0x72, 0xfe, 0x19,
12263 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12264 0x1d, 0xe8, 0x33, 0x31,
12265 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12266 0x0b, 0x1c, 0x34, 0x1d,
12267 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12268 0x33, 0x31, 0xfe, 0xe8,
12269 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12270 0x05, 0x1f, 0x35, 0xa9,
12271 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12272 0x14, 0x01, 0xaf, 0x8c,
12273 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12274 0x03, 0x45, 0x28, 0x35,
12275 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12276 0x03, 0x5c, 0xc1, 0x0c,
12277 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12278 0x89, 0x01, 0x0b, 0x1c,
12279 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12280 0xfe, 0x42, 0x58, 0xf1,
12281 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12282 0xf4, 0x06, 0xea, 0x32,
12283 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12284 0x01, 0x0b, 0x26, 0x89,
12285 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12286 0x26, 0xfe, 0xd4, 0x13,
12287 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12288 0x13, 0x1c, 0xfe, 0xd0,
12289 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12290 0x0f, 0x71, 0xff, 0x02,
12291 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12292 0x00, 0x5c, 0x04, 0x0f,
12293 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12294 0xfe, 0x00, 0x5c, 0x04,
12295 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12296 0x02, 0x00, 0x57, 0x52,
12297 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12298 0x87, 0x04, 0xfe, 0x03,
12299 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12300 0xfe, 0x00, 0x7d, 0xfe,
12301 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12302 0x14, 0x5f, 0x57, 0x3f,
12303 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12304 0x5a, 0x8d, 0x04, 0x01,
12305 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12306 0xfe, 0x96, 0x15, 0x33,
12307 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12308 0x0a, 0xfe, 0xc1, 0x59,
12309 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12310 0x21, 0x69, 0x1a, 0xee,
12311 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12312 0x30, 0xfe, 0x78, 0x10,
12313 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12314 0x98, 0xfe, 0x30, 0x00,
12315 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12316 0x98, 0xfe, 0x64, 0x00,
12317 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12318 0x10, 0x69, 0x06, 0xfe,
12319 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12320 0x18, 0x59, 0x0f, 0x06,
12321 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12322 0x43, 0xf4, 0x9f, 0xfe,
12323 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12324 0x9e, 0xfe, 0xf3, 0x10,
12325 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12326 0x17, 0xfe, 0x4d, 0xe4,
12327 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12328 0x17, 0xfe, 0x4d, 0xe4,
12329 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12330 0xf4, 0x00, 0xe9, 0x91,
12331 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12332 0x04, 0x16, 0x06, 0x01,
12333 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12334 0x0b, 0x26, 0xf3, 0x76,
12335 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12336 0x16, 0x19, 0x01, 0x0b,
12337 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12338 0x0b, 0x26, 0xb1, 0x76,
12339 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12340 0xfe, 0x48, 0x13, 0xb8,
12341 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12342 0xec, 0xfe, 0x27, 0x01,
12343 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12344 0x07, 0xfe, 0xe3, 0x00,
12345 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12346 0x22, 0xd4, 0x07, 0x06,
12347 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12348 0x07, 0x11, 0xae, 0x09,
12349 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12350 0x0e, 0x8e, 0xfe, 0x80,
12351 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12352 0x09, 0x48, 0x01, 0x0e,
12353 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12354 0x80, 0xfe, 0x80, 0x4c,
12355 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12356 0x09, 0x5d, 0x01, 0x87,
12357 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12358 0x19, 0xde, 0xfe, 0x24,
12359 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12360 0x17, 0xad, 0x9a, 0x1b,
12361 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12362 0x16, 0xfe, 0xda, 0x10,
12363 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12364 0x18, 0x58, 0x03, 0xfe,
12365 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12366 0xf4, 0x06, 0xfe, 0x3c,
12367 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12368 0x97, 0xfe, 0x38, 0x17,
12369 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12370 0x10, 0x18, 0x11, 0x75,
12371 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12372 0x2e, 0x97, 0xfe, 0x5a,
12373 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12374 0xfe, 0x98, 0xe7, 0x00,
12375 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12376 0xfe, 0x30, 0xbc, 0xfe,
12377 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12378 0xcb, 0x97, 0xfe, 0x92,
12379 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12380 0x42, 0x10, 0xfe, 0x02,
12381 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12382 0x03, 0xa1, 0xfe, 0x1d,
12383 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12384 0x9a, 0x5b, 0x41, 0xfe,
12385 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12386 0x11, 0x12, 0xfe, 0xdd,
12387 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12388 0x17, 0x15, 0x06, 0x39,
12389 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12390 0xfe, 0x7e, 0x18, 0x1e,
12391 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12392 0x12, 0xfe, 0xe1, 0x10,
12393 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12394 0x13, 0x42, 0x92, 0x09,
12395 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12396 0xf0, 0xfe, 0x00, 0xcc,
12397 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12398 0x0e, 0xfe, 0x80, 0x4c,
12399 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12400 0x24, 0x12, 0xfe, 0x14,
12401 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12402 0xe7, 0x0a, 0x10, 0xfe,
12403 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12404 0x08, 0x54, 0x1b, 0x37,
12405 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12406 0x90, 0x3a, 0xce, 0x3b,
12407 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
12408 0x13, 0xa3, 0x04, 0x09,
12409 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
12410 0x44, 0x17, 0xfe, 0xe8,
12411 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
12412 0x5d, 0x01, 0xa8, 0x09,
12413 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
12414 0x1c, 0x19, 0x03, 0xfe,
12415 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
12416 0x6b, 0xfe, 0x2e, 0x19,
12417 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
12418 0xfe, 0x0b, 0x00, 0x6b,
12419 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
12420 0x08, 0x10, 0x03, 0xfe,
12421 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
12422 0x04, 0x68, 0x54, 0xe7,
12423 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
12424 0x1a, 0xf4, 0xfe, 0x00,
12425 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
12426 0x04, 0x07, 0x7e, 0xfe,
12427 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12428 0x07, 0x1a, 0xfe, 0x5a,
12429 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
12430 0x25, 0x6d, 0xe5, 0x07,
12431 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
12432 0xa9, 0xb8, 0x04, 0x15,
12433 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
12434 0x40, 0x5c, 0x04, 0x1c,
12435 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
12436 0xf7, 0xfe, 0x82, 0xf0,
12437 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012438};
12439
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012440static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
12441static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012442
12443/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012444static unsigned char _adv_asc38C1600_buf[] = {
12445 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
12446 0x18, 0xe4, 0x01, 0x00,
12447 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
12448 0x07, 0x17, 0xc0, 0x5f,
12449 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
12450 0x85, 0xf0, 0x86, 0xf0,
12451 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
12452 0x98, 0x57, 0x01, 0xe6,
12453 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
12454 0x38, 0x54, 0x32, 0xf0,
12455 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
12456 0x00, 0xe6, 0xb1, 0xf0,
12457 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
12458 0x06, 0x13, 0x0c, 0x1c,
12459 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
12460 0xb9, 0x54, 0x00, 0x80,
12461 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
12462 0x03, 0xe6, 0x01, 0xea,
12463 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
12464 0x04, 0x13, 0xbb, 0x55,
12465 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
12466 0xbb, 0x00, 0xc0, 0x00,
12467 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
12468 0x4c, 0x1c, 0x4e, 0x1c,
12469 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
12470 0x24, 0x01, 0x3c, 0x01,
12471 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
12472 0x78, 0x01, 0x7c, 0x01,
12473 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
12474 0x6e, 0x1e, 0x02, 0x48,
12475 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
12476 0x03, 0xfc, 0x06, 0x00,
12477 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
12478 0x30, 0x1c, 0x38, 0x1c,
12479 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
12480 0x5d, 0xf0, 0xa7, 0xf0,
12481 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
12482 0x33, 0x00, 0x34, 0x00,
12483 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
12484 0x79, 0x01, 0x3c, 0x09,
12485 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
12486 0x40, 0x16, 0x50, 0x16,
12487 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
12488 0x05, 0xf0, 0x09, 0xf0,
12489 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
12490 0x9c, 0x00, 0xa4, 0x00,
12491 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
12492 0xe9, 0x09, 0x5c, 0x0c,
12493 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
12494 0x42, 0x1d, 0x08, 0x44,
12495 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
12496 0x83, 0x55, 0x83, 0x59,
12497 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
12498 0x4b, 0xf4, 0x04, 0xf8,
12499 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
12500 0xa8, 0x00, 0xaa, 0x00,
12501 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
12502 0x7a, 0x01, 0x82, 0x01,
12503 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
12504 0x68, 0x08, 0x10, 0x0d,
12505 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
12506 0xf3, 0x10, 0x06, 0x12,
12507 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
12508 0xf0, 0x35, 0x05, 0xfe,
12509 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
12510 0xfe, 0x88, 0x01, 0xff,
12511 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12512 0x00, 0xfe, 0x57, 0x24,
12513 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
12514 0x00, 0x00, 0xff, 0x08,
12515 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12516 0xff, 0xff, 0xff, 0x13,
12517 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12518 0xfe, 0x04, 0xf7, 0xe8,
12519 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
12520 0x0d, 0x51, 0x37, 0xfe,
12521 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
12522 0xfe, 0xf8, 0x01, 0xfe,
12523 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
12524 0x05, 0xfe, 0x08, 0x0f,
12525 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
12526 0x28, 0x1c, 0x03, 0xfe,
12527 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
12528 0x48, 0xf0, 0xfe, 0x90,
12529 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
12530 0x02, 0xfe, 0x46, 0xf0,
12531 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
12532 0xfe, 0x4e, 0x02, 0xfe,
12533 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
12534 0x0d, 0xa2, 0x1c, 0x07,
12535 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
12536 0x1c, 0xf5, 0xfe, 0x1e,
12537 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
12538 0xde, 0x0a, 0x81, 0x01,
12539 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
12540 0x81, 0x01, 0x5c, 0xfe,
12541 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
12542 0xfe, 0x58, 0x1c, 0x1c,
12543 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
12544 0x2b, 0xfe, 0x9e, 0x02,
12545 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
12546 0x00, 0x47, 0xb8, 0x01,
12547 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
12548 0x1a, 0x31, 0xfe, 0x69,
12549 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
12550 0x1e, 0x1e, 0x20, 0x2c,
12551 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
12552 0x44, 0x15, 0x56, 0x51,
12553 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
12554 0x01, 0x18, 0x09, 0x00,
12555 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
12556 0x18, 0xfe, 0xc8, 0x54,
12557 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
12558 0xfe, 0x02, 0xe8, 0x30,
12559 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
12560 0xfe, 0xe4, 0x01, 0xfe,
12561 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
12562 0x26, 0xf0, 0xfe, 0x66,
12563 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
12564 0xef, 0x10, 0xfe, 0x9f,
12565 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
12566 0x70, 0x37, 0xfe, 0x48,
12567 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
12568 0x21, 0xb9, 0xc7, 0x20,
12569 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
12570 0xe1, 0x2a, 0xeb, 0xfe,
12571 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
12572 0x15, 0xfe, 0xe4, 0x00,
12573 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
12574 0xfe, 0x06, 0xf0, 0xfe,
12575 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
12576 0x03, 0x81, 0x1e, 0x1b,
12577 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
12578 0xea, 0xfe, 0x46, 0x1c,
12579 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12580 0xfe, 0x48, 0x1c, 0x75,
12581 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
12582 0xe1, 0x01, 0x18, 0x77,
12583 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
12584 0x8f, 0xfe, 0x70, 0x02,
12585 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
12586 0x16, 0xfe, 0x4a, 0x04,
12587 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
12588 0x02, 0x00, 0x10, 0x01,
12589 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
12590 0xee, 0xfe, 0x4c, 0x44,
12591 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
12592 0x7b, 0xec, 0x60, 0x8d,
12593 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
12594 0x0c, 0x06, 0x28, 0xfe,
12595 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
12596 0x13, 0x34, 0xfe, 0x4c,
12597 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
12598 0x13, 0x01, 0x0c, 0x06,
12599 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
12600 0x28, 0xf9, 0x1f, 0x7f,
12601 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
12602 0xfe, 0xa4, 0x0e, 0x05,
12603 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
12604 0x9c, 0x93, 0x3a, 0x0b,
12605 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
12606 0x7d, 0x1d, 0xfe, 0x46,
12607 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
12608 0xfe, 0x87, 0x83, 0xfe,
12609 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
12610 0x13, 0x0f, 0xfe, 0x20,
12611 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
12612 0x12, 0x01, 0x38, 0x06,
12613 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
12614 0x05, 0xd0, 0x54, 0x01,
12615 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
12616 0x50, 0x12, 0x5e, 0xff,
12617 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
12618 0x00, 0x10, 0x2f, 0xfe,
12619 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
12620 0x38, 0xfe, 0x4a, 0xf0,
12621 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
12622 0x21, 0x00, 0xf1, 0x2e,
12623 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
12624 0x10, 0x2f, 0xfe, 0xd0,
12625 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
12626 0x1c, 0x00, 0x4d, 0x01,
12627 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
12628 0x28, 0xfe, 0x24, 0x12,
12629 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
12630 0x0d, 0x00, 0x01, 0x42,
12631 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
12632 0x03, 0xb6, 0x1e, 0xfe,
12633 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
12634 0xfe, 0x72, 0x06, 0x0a,
12635 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
12636 0x19, 0x16, 0xfe, 0x68,
12637 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
12638 0x03, 0x9a, 0x1e, 0xfe,
12639 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
12640 0x48, 0xfe, 0x92, 0x06,
12641 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
12642 0x58, 0xff, 0x02, 0x00,
12643 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
12644 0xfe, 0xea, 0x06, 0x01,
12645 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
12646 0xfe, 0xe0, 0x06, 0x15,
12647 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
12648 0x01, 0x84, 0xfe, 0xae,
12649 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
12650 0x1e, 0xfe, 0x1a, 0x12,
12651 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
12652 0x43, 0x48, 0x62, 0x80,
12653 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
12654 0x36, 0xfe, 0x02, 0xf6,
12655 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
12656 0xd0, 0x0d, 0x17, 0xfe,
12657 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
12658 0x9e, 0x15, 0x82, 0x01,
12659 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
12660 0x57, 0x10, 0xe6, 0x05,
12661 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
12662 0xfe, 0x9c, 0x32, 0x5f,
12663 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
12664 0xfe, 0x0a, 0xf0, 0xfe,
12665 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
12666 0xaf, 0xa0, 0x05, 0x29,
12667 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
12668 0x00, 0x01, 0x08, 0x14,
12669 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
12670 0x14, 0x00, 0x05, 0xfe,
12671 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
12672 0x12, 0xfe, 0x30, 0x13,
12673 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
12674 0x01, 0x08, 0x14, 0x00,
12675 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
12676 0x78, 0x4f, 0x0f, 0xfe,
12677 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
12678 0x28, 0x48, 0xfe, 0x6c,
12679 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
12680 0x12, 0x53, 0x63, 0x4e,
12681 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
12682 0x6c, 0x08, 0xaf, 0xa0,
12683 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
12684 0x05, 0xed, 0xfe, 0x9c,
12685 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
12686 0x1e, 0xfe, 0x99, 0x58,
12687 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
12688 0x22, 0x6b, 0x01, 0x0c,
12689 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
12690 0x1e, 0x47, 0x2c, 0x7a,
12691 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
12692 0x01, 0x0c, 0x61, 0x65,
12693 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
12694 0x16, 0xfe, 0x08, 0x50,
12695 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
12696 0x01, 0xfe, 0xce, 0x1e,
12697 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
12698 0x01, 0xfe, 0xfe, 0x1e,
12699 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
12700 0x10, 0x01, 0x0c, 0x06,
12701 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
12702 0x10, 0x6a, 0x22, 0x6b,
12703 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
12704 0xfe, 0x9f, 0x83, 0x33,
12705 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
12706 0x3a, 0x0b, 0xfe, 0xc6,
12707 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
12708 0x01, 0xfe, 0xce, 0x1e,
12709 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
12710 0x04, 0xfe, 0xc0, 0x93,
12711 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
12712 0x10, 0x4b, 0x22, 0x4c,
12713 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
12714 0x4e, 0x11, 0x2f, 0xfe,
12715 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
12716 0x3c, 0x37, 0x88, 0xf5,
12717 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
12718 0xd3, 0xfe, 0x42, 0x0a,
12719 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
12720 0x05, 0x29, 0x01, 0x41,
12721 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
12722 0xfe, 0x14, 0x12, 0x01,
12723 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
12724 0x2e, 0x1c, 0x05, 0xfe,
12725 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
12726 0xfe, 0x2c, 0x1c, 0xfe,
12727 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
12728 0x92, 0x10, 0xc4, 0xf6,
12729 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
12730 0xe7, 0x10, 0xfe, 0x2b,
12731 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
12732 0xac, 0xfe, 0xd2, 0xf0,
12733 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
12734 0x1b, 0xbf, 0xd4, 0x5b,
12735 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
12736 0x5e, 0x32, 0x1f, 0x7f,
12737 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
12738 0x05, 0x70, 0xfe, 0x74,
12739 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
12740 0x0f, 0x4d, 0x01, 0xfe,
12741 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
12742 0x0d, 0x2b, 0xfe, 0xe2,
12743 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
12744 0xfe, 0x88, 0x13, 0x21,
12745 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
12746 0x83, 0x83, 0xfe, 0xc9,
12747 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
12748 0x91, 0x04, 0xfe, 0x84,
12749 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
12750 0xfe, 0xcb, 0x57, 0x0b,
12751 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
12752 0x6a, 0x3b, 0x6b, 0x10,
12753 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
12754 0x20, 0x6e, 0xdb, 0x64,
12755 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
12756 0xfe, 0x04, 0xfa, 0x64,
12757 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
12758 0x10, 0x98, 0x91, 0x6c,
12759 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
12760 0x4b, 0x7e, 0x4c, 0x01,
12761 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
12762 0x58, 0xfe, 0x91, 0x58,
12763 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
12764 0x1b, 0x40, 0x01, 0x0c,
12765 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
12766 0xfe, 0x10, 0x90, 0x04,
12767 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
12768 0x79, 0x0b, 0x0e, 0xfe,
12769 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
12770 0x01, 0x0c, 0x06, 0x0d,
12771 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
12772 0x0c, 0x58, 0xfe, 0x8d,
12773 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
12774 0x83, 0x33, 0x0b, 0x0e,
12775 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
12776 0x19, 0xfe, 0x19, 0x41,
12777 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
12778 0x19, 0xfe, 0x44, 0x00,
12779 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
12780 0x4c, 0xfe, 0x0c, 0x51,
12781 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
12782 0x76, 0x10, 0xac, 0xfe,
12783 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
12784 0xe3, 0x23, 0x07, 0xfe,
12785 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
12786 0xcc, 0x0c, 0x1f, 0x92,
12787 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
12788 0x0c, 0xfe, 0x3e, 0x10,
12789 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
12790 0xfe, 0xcb, 0xf0, 0xfe,
12791 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
12792 0xf4, 0x0c, 0x19, 0x94,
12793 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
12794 0xfe, 0xcc, 0xf0, 0xef,
12795 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
12796 0x4e, 0x11, 0x2f, 0xfe,
12797 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
12798 0x3c, 0x37, 0x88, 0xf5,
12799 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
12800 0x2f, 0xfe, 0x3e, 0x0d,
12801 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
12802 0xd2, 0x9f, 0xd3, 0x9f,
12803 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
12804 0xc5, 0x75, 0xd7, 0x99,
12805 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
12806 0x9c, 0x2f, 0xfe, 0x8c,
12807 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
12808 0x42, 0x00, 0x05, 0x70,
12809 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
12810 0x0d, 0xfe, 0x44, 0x13,
12811 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
12812 0xfe, 0xda, 0x0e, 0x0a,
12813 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
12814 0x10, 0x01, 0xfe, 0xf4,
12815 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
12816 0x15, 0x56, 0x01, 0x85,
12817 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
12818 0xcc, 0x10, 0x01, 0xa7,
12819 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
12820 0xfe, 0x99, 0x83, 0xfe,
12821 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
12822 0x43, 0x00, 0xfe, 0xa2,
12823 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
12824 0x00, 0x1d, 0x40, 0x15,
12825 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
12826 0xfe, 0x3a, 0x03, 0x01,
12827 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
12828 0x76, 0x06, 0x12, 0xfe,
12829 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
12830 0xfe, 0x9d, 0xf0, 0xfe,
12831 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
12832 0x0c, 0x61, 0x12, 0x44,
12833 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
12834 0xfe, 0x2e, 0x10, 0x19,
12835 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
12836 0xfe, 0x41, 0x00, 0xa2,
12837 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
12838 0xea, 0x4f, 0xfe, 0x04,
12839 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
12840 0x35, 0xfe, 0x12, 0x1c,
12841 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
12842 0xfe, 0xd4, 0x11, 0x05,
12843 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
12844 0xce, 0x45, 0x31, 0x51,
12845 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
12846 0x67, 0xfe, 0x98, 0x56,
12847 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
12848 0x0c, 0x06, 0x28, 0xfe,
12849 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
12850 0xfe, 0xfa, 0x14, 0xfe,
12851 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
12852 0xfe, 0xe0, 0x14, 0xfe,
12853 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
12854 0xfe, 0xad, 0x13, 0x05,
12855 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
12856 0xe7, 0xfe, 0x08, 0x1c,
12857 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
12858 0x48, 0x55, 0xa5, 0x3b,
12859 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
12860 0xf0, 0x1a, 0x03, 0xfe,
12861 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
12862 0xec, 0xe7, 0x53, 0x00,
12863 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
12864 0x01, 0xfe, 0x62, 0x1b,
12865 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
12866 0xea, 0xe7, 0x53, 0x92,
12867 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
12868 0xfe, 0x38, 0x01, 0x23,
12869 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
12870 0x01, 0x01, 0xfe, 0x1e,
12871 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
12872 0x26, 0x02, 0x21, 0x96,
12873 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
12874 0xc3, 0xfe, 0xe1, 0x10,
12875 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
12876 0xfe, 0x03, 0xdc, 0xfe,
12877 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
12878 0x00, 0xcc, 0x02, 0xfe,
12879 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
12880 0x0f, 0xfe, 0x1c, 0x80,
12881 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
12882 0x0f, 0xfe, 0x1e, 0x80,
12883 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
12884 0x1d, 0x80, 0x04, 0xfe,
12885 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
12886 0x1e, 0xac, 0xfe, 0x14,
12887 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
12888 0x1f, 0xfe, 0x30, 0xf4,
12889 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
12890 0x56, 0xfb, 0x01, 0xfe,
12891 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
12892 0xfe, 0x00, 0x1d, 0x15,
12893 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
12894 0x22, 0x1b, 0xfe, 0x1e,
12895 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
12896 0x96, 0x90, 0x04, 0xfe,
12897 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
12898 0x01, 0x01, 0x0c, 0x06,
12899 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
12900 0x0e, 0x77, 0xfe, 0x01,
12901 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
12902 0x21, 0x2c, 0xfe, 0x00,
12903 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
12904 0x06, 0x58, 0x03, 0xfe,
12905 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
12906 0x03, 0xfe, 0xb2, 0x00,
12907 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
12908 0x66, 0x10, 0x55, 0x10,
12909 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
12910 0x54, 0x2b, 0xfe, 0x88,
12911 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
12912 0x91, 0x54, 0x2b, 0xfe,
12913 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
12914 0x00, 0x40, 0x8d, 0x2c,
12915 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
12916 0x12, 0x1c, 0x75, 0xfe,
12917 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
12918 0x14, 0xfe, 0x0e, 0x47,
12919 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
12920 0xa7, 0x90, 0x34, 0x60,
12921 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
12922 0x09, 0x56, 0xfe, 0x34,
12923 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
12924 0xfe, 0x45, 0x48, 0x01,
12925 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
12926 0x09, 0x1a, 0xa5, 0x0a,
12927 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
12928 0xfe, 0x14, 0x56, 0xfe,
12929 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
12930 0xec, 0xb8, 0xfe, 0x9e,
12931 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
12932 0xf4, 0xfe, 0xdd, 0x10,
12933 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
12934 0x12, 0x09, 0x0d, 0xfe,
12935 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
12936 0x13, 0x09, 0xfe, 0x23,
12937 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
12938 0x24, 0xfe, 0x12, 0x12,
12939 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
12940 0xae, 0x41, 0x02, 0x32,
12941 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
12942 0x35, 0x32, 0x01, 0x43,
12943 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
12944 0x13, 0x01, 0x0c, 0x06,
12945 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
12946 0xe5, 0x55, 0xb0, 0xfe,
12947 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
12948 0xfe, 0xb6, 0x0e, 0x10,
12949 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
12950 0x88, 0x20, 0x6e, 0x01,
12951 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
12952 0x55, 0xfe, 0x04, 0xfa,
12953 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
12954 0xfe, 0x40, 0x56, 0xfe,
12955 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
12956 0x44, 0x55, 0xfe, 0xe5,
12957 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
12958 0x68, 0x22, 0x69, 0x01,
12959 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
12960 0x6b, 0xfe, 0x2c, 0x50,
12961 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
12962 0x50, 0x03, 0x68, 0x3b,
12963 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
12964 0x40, 0x50, 0xfe, 0xc2,
12965 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
12966 0x16, 0x3d, 0x27, 0x25,
12967 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
12968 0xa6, 0x23, 0x3f, 0x1b,
12969 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
12970 0xfe, 0x0a, 0x55, 0x31,
12971 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
12972 0x51, 0x05, 0x72, 0x01,
12973 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
12974 0x2a, 0x3c, 0x16, 0xc0,
12975 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
12976 0xfe, 0x66, 0x15, 0x05,
12977 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
12978 0x2b, 0x3d, 0x01, 0x08,
12979 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
12980 0xb6, 0x1e, 0x83, 0x01,
12981 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
12982 0x07, 0x90, 0x3f, 0x01,
12983 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
12984 0x01, 0x43, 0x09, 0x82,
12985 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
12986 0x05, 0x72, 0xfe, 0xc0,
12987 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
12988 0x32, 0x01, 0x08, 0x17,
12989 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
12990 0x3d, 0x27, 0x25, 0xbd,
12991 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
12992 0xe8, 0x14, 0x01, 0xa6,
12993 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
12994 0x0e, 0x12, 0x01, 0x43,
12995 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
12996 0x01, 0x08, 0x17, 0x73,
12997 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
12998 0x27, 0x25, 0xbd, 0x09,
12999 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
13000 0xb6, 0x14, 0x86, 0xa8,
13001 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
13002 0x82, 0x4e, 0x05, 0x72,
13003 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
13004 0xfe, 0xc0, 0x19, 0x05,
13005 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
13006 0xcc, 0x01, 0x08, 0x26,
13007 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
13008 0xcc, 0x15, 0x5e, 0x32,
13009 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
13010 0xad, 0x23, 0xfe, 0xff,
13011 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
13012 0x00, 0x57, 0x52, 0xad,
13013 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
13014 0x02, 0x00, 0x57, 0x52,
13015 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
13016 0x02, 0x13, 0x58, 0xff,
13017 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
13018 0x5c, 0x0a, 0x55, 0x01,
13019 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
13020 0xff, 0x03, 0x00, 0x54,
13021 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
13022 0x7c, 0x3a, 0x0b, 0x0e,
13023 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
13024 0xfe, 0x1a, 0xf7, 0x00,
13025 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
13026 0xda, 0x6d, 0x02, 0xfe,
13027 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
13028 0x02, 0x01, 0xc6, 0xfe,
13029 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
13030 0x25, 0xbe, 0x01, 0x08,
13031 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
13032 0x03, 0x9a, 0x1e, 0xfe,
13033 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
13034 0x48, 0xfe, 0x08, 0x17,
13035 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
13036 0x17, 0x4d, 0x13, 0x07,
13037 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
13038 0xff, 0x02, 0x83, 0x55,
13039 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
13040 0x17, 0x1c, 0x63, 0x13,
13041 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
13042 0x00, 0xb0, 0xfe, 0x80,
13043 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
13044 0x53, 0x07, 0xfe, 0x60,
13045 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
13046 0x00, 0x1c, 0x95, 0x13,
13047 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
13048 0xfe, 0x43, 0xf4, 0x96,
13049 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
13050 0xf4, 0x94, 0xf6, 0x8b,
13051 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
13052 0xda, 0x17, 0x62, 0x49,
13053 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
13054 0x71, 0x50, 0x26, 0xfe,
13055 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
13056 0x58, 0x02, 0x50, 0x13,
13057 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
13058 0x25, 0xbe, 0xfe, 0x03,
13059 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
13060 0x0a, 0x01, 0x08, 0x16,
13061 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13062 0x01, 0x08, 0x16, 0xa9,
13063 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13064 0x08, 0x16, 0xa9, 0x27,
13065 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13066 0x01, 0x38, 0x06, 0x24,
13067 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13068 0x78, 0x03, 0x9a, 0x1e,
13069 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13070 0xfe, 0x40, 0x5a, 0x23,
13071 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13072 0x80, 0x48, 0xfe, 0xaa,
13073 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13074 0xfe, 0xac, 0x1d, 0xfe,
13075 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13076 0x43, 0x48, 0x2d, 0x93,
13077 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13078 0x36, 0xfe, 0x34, 0xf4,
13079 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13080 0x28, 0x10, 0xfe, 0xc0,
13081 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13082 0x18, 0x45, 0xfe, 0x1c,
13083 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13084 0x19, 0xfe, 0x04, 0xf4,
13085 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13086 0x21, 0xfe, 0x7f, 0x01,
13087 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13088 0x7e, 0x01, 0xfe, 0xc8,
13089 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13090 0x21, 0xfe, 0x81, 0x01,
13091 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13092 0x13, 0x0d, 0x02, 0x14,
13093 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13094 0xfe, 0x82, 0x19, 0x14,
13095 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13096 0x08, 0x02, 0x14, 0x07,
13097 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13098 0x01, 0x08, 0x17, 0xc1,
13099 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13100 0x08, 0x02, 0x50, 0x02,
13101 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13102 0x14, 0x12, 0x01, 0x08,
13103 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13104 0x08, 0x17, 0x74, 0xfe,
13105 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13106 0x74, 0x5f, 0xcc, 0x01,
13107 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13108 0xfe, 0x49, 0xf4, 0x00,
13109 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13110 0x02, 0x00, 0x10, 0x2f,
13111 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13112 0x16, 0xfe, 0x64, 0x1a,
13113 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13114 0x61, 0x07, 0x44, 0x02,
13115 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13116 0x13, 0x0a, 0x9d, 0x01,
13117 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13118 0xfe, 0x80, 0xe7, 0x1a,
13119 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13120 0x0a, 0x5a, 0x01, 0x18,
13121 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13122 0x7e, 0x1e, 0xfe, 0x80,
13123 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13124 0xfe, 0x80, 0x4c, 0x0a,
13125 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13126 0xfe, 0x19, 0xde, 0xfe,
13127 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13128 0x2a, 0x1c, 0xfa, 0xb3,
13129 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13130 0xf4, 0x1a, 0xfe, 0xfa,
13131 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13132 0xfe, 0x18, 0x58, 0x03,
13133 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13134 0xfe, 0x30, 0xf4, 0x07,
13135 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13136 0xf7, 0x24, 0xb1, 0xfe,
13137 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13138 0xfe, 0xba, 0x10, 0x1c,
13139 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13140 0x1d, 0xf7, 0x54, 0xb1,
13141 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13142 0xaf, 0x19, 0xfe, 0x98,
13143 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13144 0x1a, 0x87, 0x8b, 0x0f,
13145 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13146 0xfe, 0x32, 0x90, 0x04,
13147 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13148 0x7c, 0x12, 0xfe, 0x0f,
13149 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13150 0x31, 0x02, 0xc9, 0x2b,
13151 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13152 0x6a, 0xfe, 0x19, 0xfe,
13153 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13154 0x1b, 0xfe, 0x36, 0x14,
13155 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13156 0xfe, 0x80, 0xe7, 0x1a,
13157 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13158 0x30, 0xfe, 0x12, 0x45,
13159 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13160 0x39, 0xf0, 0x75, 0x26,
13161 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13162 0xe3, 0x23, 0x07, 0xfe,
13163 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13164 0x56, 0xfe, 0x3c, 0x13,
13165 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13166 0x01, 0x18, 0xcb, 0xfe,
13167 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13168 0xfe, 0x00, 0xcc, 0xcb,
13169 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13170 0xfe, 0x80, 0x4c, 0x01,
13171 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13172 0x12, 0xfe, 0x14, 0x56,
13173 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13174 0x0d, 0x19, 0xfe, 0x15,
13175 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13176 0x83, 0xfe, 0x18, 0x80,
13177 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13178 0x90, 0xfe, 0xba, 0x90,
13179 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13180 0x21, 0xb9, 0x88, 0x20,
13181 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13182 0x18, 0xfe, 0x49, 0x44,
13183 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13184 0x1a, 0xa4, 0x0a, 0x67,
13185 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13186 0x1d, 0x7b, 0xfe, 0x52,
13187 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13188 0x4e, 0xe4, 0xdd, 0x7b,
13189 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13190 0xfe, 0x4e, 0xe4, 0xfe,
13191 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13192 0xfe, 0x08, 0x10, 0x03,
13193 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13194 0x68, 0x54, 0xfe, 0xf1,
13195 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13196 0xfe, 0x1a, 0xf4, 0xfe,
13197 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13198 0x09, 0x92, 0xfe, 0x5a,
13199 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13200 0x5a, 0xf0, 0xfe, 0xc8,
13201 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13202 0x1a, 0x10, 0x09, 0x0d,
13203 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13204 0x1f, 0x93, 0x01, 0x42,
13205 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13206 0xfe, 0x14, 0xf0, 0x08,
13207 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13208 0xfe, 0x82, 0xf0, 0xfe,
13209 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13210 0x02, 0x0f, 0xfe, 0x18,
13211 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13212 0x80, 0x04, 0xfe, 0x82,
13213 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13214 0x83, 0x33, 0x0b, 0x0e,
13215 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13216 0x02, 0x0f, 0xfe, 0x04,
13217 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13218 0x80, 0x04, 0xfe, 0x80,
13219 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13220 0xfe, 0x99, 0x83, 0xfe,
13221 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13222 0x83, 0xfe, 0xce, 0x47,
13223 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13224 0x0b, 0x0e, 0x02, 0x0f,
13225 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13226 0xfe, 0x08, 0x90, 0x04,
13227 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13228 0xfe, 0x8a, 0x93, 0x79,
13229 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13230 0x0b, 0x0e, 0x02, 0x0f,
13231 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13232 0xfe, 0x3c, 0x90, 0x04,
13233 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13234 0x04, 0xfe, 0x83, 0x83,
13235 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013236};
13237
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013238static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13239static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013240
13241/* a_init.c */
13242/*
13243 * EEPROM Configuration.
13244 *
13245 * All drivers should use this structure to set the default EEPROM
13246 * configuration. The BIOS now uses this structure when it is built.
13247 * Additional structure information can be found in a_condor.h where
13248 * the structure is defined.
13249 *
13250 * The *_Field_IsChar structs are needed to correct for endianness.
13251 * These values are read from the board 16 bits at a time directly
13252 * into the structs. Because some fields are char, the values will be
13253 * in the wrong order. The *_Field_IsChar tells when to flip the
13254 * bytes. Data read and written to PCI memory is automatically swapped
13255 * on big-endian platforms so char fields read as words are actually being
13256 * unswapped on big-endian platforms.
13257 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013258static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013259 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13260 0x0000, /* cfg_msw */
13261 0xFFFF, /* disc_enable */
13262 0xFFFF, /* wdtr_able */
13263 0xFFFF, /* sdtr_able */
13264 0xFFFF, /* start_motor */
13265 0xFFFF, /* tagqng_able */
13266 0xFFFF, /* bios_scan */
13267 0, /* scam_tolerant */
13268 7, /* adapter_scsi_id */
13269 0, /* bios_boot_delay */
13270 3, /* scsi_reset_delay */
13271 0, /* bios_id_lun */
13272 0, /* termination */
13273 0, /* reserved1 */
13274 0xFFE7, /* bios_ctrl */
13275 0xFFFF, /* ultra_able */
13276 0, /* reserved2 */
13277 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13278 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13279 0, /* dvc_cntl */
13280 0, /* bug_fix */
13281 0, /* serial_number_word1 */
13282 0, /* serial_number_word2 */
13283 0, /* serial_number_word3 */
13284 0, /* check_sum */
13285 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13286 , /* oem_name[16] */
13287 0, /* dvc_err_code */
13288 0, /* adv_err_code */
13289 0, /* adv_err_addr */
13290 0, /* saved_dvc_err_code */
13291 0, /* saved_adv_err_code */
13292 0, /* saved_adv_err_addr */
13293 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013294};
13295
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013296static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013297 0, /* cfg_lsw */
13298 0, /* cfg_msw */
13299 0, /* -disc_enable */
13300 0, /* wdtr_able */
13301 0, /* sdtr_able */
13302 0, /* start_motor */
13303 0, /* tagqng_able */
13304 0, /* bios_scan */
13305 0, /* scam_tolerant */
13306 1, /* adapter_scsi_id */
13307 1, /* bios_boot_delay */
13308 1, /* scsi_reset_delay */
13309 1, /* bios_id_lun */
13310 1, /* termination */
13311 1, /* reserved1 */
13312 0, /* bios_ctrl */
13313 0, /* ultra_able */
13314 0, /* reserved2 */
13315 1, /* max_host_qng */
13316 1, /* max_dvc_qng */
13317 0, /* dvc_cntl */
13318 0, /* bug_fix */
13319 0, /* serial_number_word1 */
13320 0, /* serial_number_word2 */
13321 0, /* serial_number_word3 */
13322 0, /* check_sum */
13323 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13324 , /* oem_name[16] */
13325 0, /* dvc_err_code */
13326 0, /* adv_err_code */
13327 0, /* adv_err_addr */
13328 0, /* saved_dvc_err_code */
13329 0, /* saved_adv_err_code */
13330 0, /* saved_adv_err_addr */
13331 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013332};
13333
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013334static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013335 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13336 0x0000, /* 01 cfg_msw */
13337 0xFFFF, /* 02 disc_enable */
13338 0xFFFF, /* 03 wdtr_able */
13339 0x4444, /* 04 sdtr_speed1 */
13340 0xFFFF, /* 05 start_motor */
13341 0xFFFF, /* 06 tagqng_able */
13342 0xFFFF, /* 07 bios_scan */
13343 0, /* 08 scam_tolerant */
13344 7, /* 09 adapter_scsi_id */
13345 0, /* bios_boot_delay */
13346 3, /* 10 scsi_reset_delay */
13347 0, /* bios_id_lun */
13348 0, /* 11 termination_se */
13349 0, /* termination_lvd */
13350 0xFFE7, /* 12 bios_ctrl */
13351 0x4444, /* 13 sdtr_speed2 */
13352 0x4444, /* 14 sdtr_speed3 */
13353 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13354 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13355 0, /* 16 dvc_cntl */
13356 0x4444, /* 17 sdtr_speed4 */
13357 0, /* 18 serial_number_word1 */
13358 0, /* 19 serial_number_word2 */
13359 0, /* 20 serial_number_word3 */
13360 0, /* 21 check_sum */
13361 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13362 , /* 22-29 oem_name[16] */
13363 0, /* 30 dvc_err_code */
13364 0, /* 31 adv_err_code */
13365 0, /* 32 adv_err_addr */
13366 0, /* 33 saved_dvc_err_code */
13367 0, /* 34 saved_adv_err_code */
13368 0, /* 35 saved_adv_err_addr */
13369 0, /* 36 reserved */
13370 0, /* 37 reserved */
13371 0, /* 38 reserved */
13372 0, /* 39 reserved */
13373 0, /* 40 reserved */
13374 0, /* 41 reserved */
13375 0, /* 42 reserved */
13376 0, /* 43 reserved */
13377 0, /* 44 reserved */
13378 0, /* 45 reserved */
13379 0, /* 46 reserved */
13380 0, /* 47 reserved */
13381 0, /* 48 reserved */
13382 0, /* 49 reserved */
13383 0, /* 50 reserved */
13384 0, /* 51 reserved */
13385 0, /* 52 reserved */
13386 0, /* 53 reserved */
13387 0, /* 54 reserved */
13388 0, /* 55 reserved */
13389 0, /* 56 cisptr_lsw */
13390 0, /* 57 cisprt_msw */
13391 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13392 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13393 0, /* 60 reserved */
13394 0, /* 61 reserved */
13395 0, /* 62 reserved */
13396 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013397};
13398
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013399static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013400 0, /* 00 cfg_lsw */
13401 0, /* 01 cfg_msw */
13402 0, /* 02 disc_enable */
13403 0, /* 03 wdtr_able */
13404 0, /* 04 sdtr_speed1 */
13405 0, /* 05 start_motor */
13406 0, /* 06 tagqng_able */
13407 0, /* 07 bios_scan */
13408 0, /* 08 scam_tolerant */
13409 1, /* 09 adapter_scsi_id */
13410 1, /* bios_boot_delay */
13411 1, /* 10 scsi_reset_delay */
13412 1, /* bios_id_lun */
13413 1, /* 11 termination_se */
13414 1, /* termination_lvd */
13415 0, /* 12 bios_ctrl */
13416 0, /* 13 sdtr_speed2 */
13417 0, /* 14 sdtr_speed3 */
13418 1, /* 15 max_host_qng */
13419 1, /* max_dvc_qng */
13420 0, /* 16 dvc_cntl */
13421 0, /* 17 sdtr_speed4 */
13422 0, /* 18 serial_number_word1 */
13423 0, /* 19 serial_number_word2 */
13424 0, /* 20 serial_number_word3 */
13425 0, /* 21 check_sum */
13426 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13427 , /* 22-29 oem_name[16] */
13428 0, /* 30 dvc_err_code */
13429 0, /* 31 adv_err_code */
13430 0, /* 32 adv_err_addr */
13431 0, /* 33 saved_dvc_err_code */
13432 0, /* 34 saved_adv_err_code */
13433 0, /* 35 saved_adv_err_addr */
13434 0, /* 36 reserved */
13435 0, /* 37 reserved */
13436 0, /* 38 reserved */
13437 0, /* 39 reserved */
13438 0, /* 40 reserved */
13439 0, /* 41 reserved */
13440 0, /* 42 reserved */
13441 0, /* 43 reserved */
13442 0, /* 44 reserved */
13443 0, /* 45 reserved */
13444 0, /* 46 reserved */
13445 0, /* 47 reserved */
13446 0, /* 48 reserved */
13447 0, /* 49 reserved */
13448 0, /* 50 reserved */
13449 0, /* 51 reserved */
13450 0, /* 52 reserved */
13451 0, /* 53 reserved */
13452 0, /* 54 reserved */
13453 0, /* 55 reserved */
13454 0, /* 56 cisptr_lsw */
13455 0, /* 57 cisprt_msw */
13456 0, /* 58 subsysvid */
13457 0, /* 59 subsysid */
13458 0, /* 60 reserved */
13459 0, /* 61 reserved */
13460 0, /* 62 reserved */
13461 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013462};
13463
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013464static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013465 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13466 0x0000, /* 01 cfg_msw */
13467 0xFFFF, /* 02 disc_enable */
13468 0xFFFF, /* 03 wdtr_able */
13469 0x5555, /* 04 sdtr_speed1 */
13470 0xFFFF, /* 05 start_motor */
13471 0xFFFF, /* 06 tagqng_able */
13472 0xFFFF, /* 07 bios_scan */
13473 0, /* 08 scam_tolerant */
13474 7, /* 09 adapter_scsi_id */
13475 0, /* bios_boot_delay */
13476 3, /* 10 scsi_reset_delay */
13477 0, /* bios_id_lun */
13478 0, /* 11 termination_se */
13479 0, /* termination_lvd */
13480 0xFFE7, /* 12 bios_ctrl */
13481 0x5555, /* 13 sdtr_speed2 */
13482 0x5555, /* 14 sdtr_speed3 */
13483 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13484 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13485 0, /* 16 dvc_cntl */
13486 0x5555, /* 17 sdtr_speed4 */
13487 0, /* 18 serial_number_word1 */
13488 0, /* 19 serial_number_word2 */
13489 0, /* 20 serial_number_word3 */
13490 0, /* 21 check_sum */
13491 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13492 , /* 22-29 oem_name[16] */
13493 0, /* 30 dvc_err_code */
13494 0, /* 31 adv_err_code */
13495 0, /* 32 adv_err_addr */
13496 0, /* 33 saved_dvc_err_code */
13497 0, /* 34 saved_adv_err_code */
13498 0, /* 35 saved_adv_err_addr */
13499 0, /* 36 reserved */
13500 0, /* 37 reserved */
13501 0, /* 38 reserved */
13502 0, /* 39 reserved */
13503 0, /* 40 reserved */
13504 0, /* 41 reserved */
13505 0, /* 42 reserved */
13506 0, /* 43 reserved */
13507 0, /* 44 reserved */
13508 0, /* 45 reserved */
13509 0, /* 46 reserved */
13510 0, /* 47 reserved */
13511 0, /* 48 reserved */
13512 0, /* 49 reserved */
13513 0, /* 50 reserved */
13514 0, /* 51 reserved */
13515 0, /* 52 reserved */
13516 0, /* 53 reserved */
13517 0, /* 54 reserved */
13518 0, /* 55 reserved */
13519 0, /* 56 cisptr_lsw */
13520 0, /* 57 cisprt_msw */
13521 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13522 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
13523 0, /* 60 reserved */
13524 0, /* 61 reserved */
13525 0, /* 62 reserved */
13526 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013527};
13528
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013529static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013530 0, /* 00 cfg_lsw */
13531 0, /* 01 cfg_msw */
13532 0, /* 02 disc_enable */
13533 0, /* 03 wdtr_able */
13534 0, /* 04 sdtr_speed1 */
13535 0, /* 05 start_motor */
13536 0, /* 06 tagqng_able */
13537 0, /* 07 bios_scan */
13538 0, /* 08 scam_tolerant */
13539 1, /* 09 adapter_scsi_id */
13540 1, /* bios_boot_delay */
13541 1, /* 10 scsi_reset_delay */
13542 1, /* bios_id_lun */
13543 1, /* 11 termination_se */
13544 1, /* termination_lvd */
13545 0, /* 12 bios_ctrl */
13546 0, /* 13 sdtr_speed2 */
13547 0, /* 14 sdtr_speed3 */
13548 1, /* 15 max_host_qng */
13549 1, /* max_dvc_qng */
13550 0, /* 16 dvc_cntl */
13551 0, /* 17 sdtr_speed4 */
13552 0, /* 18 serial_number_word1 */
13553 0, /* 19 serial_number_word2 */
13554 0, /* 20 serial_number_word3 */
13555 0, /* 21 check_sum */
13556 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13557 , /* 22-29 oem_name[16] */
13558 0, /* 30 dvc_err_code */
13559 0, /* 31 adv_err_code */
13560 0, /* 32 adv_err_addr */
13561 0, /* 33 saved_dvc_err_code */
13562 0, /* 34 saved_adv_err_code */
13563 0, /* 35 saved_adv_err_addr */
13564 0, /* 36 reserved */
13565 0, /* 37 reserved */
13566 0, /* 38 reserved */
13567 0, /* 39 reserved */
13568 0, /* 40 reserved */
13569 0, /* 41 reserved */
13570 0, /* 42 reserved */
13571 0, /* 43 reserved */
13572 0, /* 44 reserved */
13573 0, /* 45 reserved */
13574 0, /* 46 reserved */
13575 0, /* 47 reserved */
13576 0, /* 48 reserved */
13577 0, /* 49 reserved */
13578 0, /* 50 reserved */
13579 0, /* 51 reserved */
13580 0, /* 52 reserved */
13581 0, /* 53 reserved */
13582 0, /* 54 reserved */
13583 0, /* 55 reserved */
13584 0, /* 56 cisptr_lsw */
13585 0, /* 57 cisprt_msw */
13586 0, /* 58 subsysvid */
13587 0, /* 59 subsysid */
13588 0, /* 60 reserved */
13589 0, /* 61 reserved */
13590 0, /* 62 reserved */
13591 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013592};
13593
13594/*
13595 * Initialize the ADV_DVC_VAR structure.
13596 *
13597 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13598 *
13599 * For a non-fatal error return a warning code. If there are no warnings
13600 * then 0 is returned.
13601 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013602static int __devinit AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013603{
Matthew Wilcox9649af32007-07-26 21:51:47 -060013604 unsigned short warn_code = 0;
13605 AdvPortAddr iop_base = asc_dvc->iop_base;
13606 struct pci_dev *pdev = to_pci_dev(asc_dvc->cfg->dev);
13607 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013608 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013609
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013610 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013611
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013612 /*
13613 * Save the state of the PCI Configuration Command Register
13614 * "Parity Error Response Control" Bit. If the bit is clear (0),
13615 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
13616 * DMA parity errors.
13617 */
13618 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060013619 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
13620 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013621 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013622
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013623 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
13624 ADV_LIB_VERSION_MINOR;
13625 asc_dvc->cfg->chip_version =
13626 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013627
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013628 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
13629 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
13630 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013631
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013632 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
13633 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
13634 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013635
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013636 /*
13637 * Reset the chip to start and allow register writes.
13638 */
13639 if (AdvFindSignature(iop_base) == 0) {
13640 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
13641 return ADV_ERROR;
13642 } else {
13643 /*
13644 * The caller must set 'chip_type' to a valid setting.
13645 */
13646 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
13647 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
13648 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
13649 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13650 return ADV_ERROR;
13651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013653 /*
13654 * Reset Chip.
13655 */
13656 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13657 ADV_CTRL_REG_CMD_RESET);
13658 DvcSleepMilliSecond(100);
13659 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13660 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013661
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013662 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013663 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013664 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013665 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013666 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013667 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013668 }
13669 warn_code |= status;
13670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013671
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013672 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013673}
13674
13675/*
13676 * Initialize the ASC-3550.
13677 *
13678 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13679 *
13680 * For a non-fatal error return a warning code. If there are no warnings
13681 * then 0 is returned.
13682 *
13683 * Needed after initialization for error recovery.
13684 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013685static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013686{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013687 AdvPortAddr iop_base;
13688 ushort warn_code;
13689 ADV_DCNT sum;
13690 int begin_addr;
13691 int end_addr;
13692 ushort code_sum;
13693 int word;
13694 int j;
13695 int adv_asc3550_expanded_size;
13696 ADV_CARR_T *carrp;
13697 ADV_DCNT contig_len;
13698 ADV_SDCNT buf_size;
13699 ADV_PADDR carr_paddr;
13700 int i;
13701 ushort scsi_cfg1;
13702 uchar tid;
13703 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
13704 ushort wdtr_able = 0, sdtr_able, tagqng_able;
13705 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013706
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013707 /* If there is already an error, don't continue. */
13708 if (asc_dvc->err_code != 0) {
13709 return ADV_ERROR;
13710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013711
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013712 /*
13713 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
13714 */
13715 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
13716 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13717 return ADV_ERROR;
13718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013720 warn_code = 0;
13721 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013722
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013723 /*
13724 * Save the RISC memory BIOS region before writing the microcode.
13725 * The BIOS may already be loaded and using its RISC LRAM region
13726 * so its region must be saved and restored.
13727 *
13728 * Note: This code makes the assumption, which is currently true,
13729 * that a chip reset does not clear RISC LRAM.
13730 */
13731 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13732 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13733 bios_mem[i]);
13734 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013735
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013736 /*
13737 * Save current per TID negotiated values.
13738 */
13739 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
13740 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013741
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013742 bios_version =
13743 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
13744 major = (bios_version >> 12) & 0xF;
13745 minor = (bios_version >> 8) & 0xF;
13746 if (major < 3 || (major == 3 && minor == 1)) {
13747 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
13748 AdvReadWordLram(iop_base, 0x120, wdtr_able);
13749 } else {
13750 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13751 }
13752 }
13753 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13754 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13755 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13756 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13757 max_cmd[tid]);
13758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013759
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013760 /*
13761 * Load the Microcode
13762 *
13763 * Write the microcode image to RISC memory starting at address 0.
13764 */
13765 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
13766 /* Assume the following compressed format of the microcode buffer:
13767 *
13768 * 254 word (508 byte) table indexed by byte code followed
13769 * by the following byte codes:
13770 *
13771 * 1-Byte Code:
13772 * 00: Emit word 0 in table.
13773 * 01: Emit word 1 in table.
13774 * .
13775 * FD: Emit word 253 in table.
13776 *
13777 * Multi-Byte Code:
13778 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
13779 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
13780 */
13781 word = 0;
13782 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
13783 if (_adv_asc3550_buf[i] == 0xff) {
13784 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
13785 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13786 _adv_asc3550_buf
13787 [i +
13788 3] << 8) |
13789 _adv_asc3550_buf
13790 [i + 2]));
13791 word++;
13792 }
13793 i += 3;
13794 } else if (_adv_asc3550_buf[i] == 0xfe) {
13795 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13796 _adv_asc3550_buf[i +
13797 2]
13798 << 8) |
13799 _adv_asc3550_buf[i +
13800 1]));
13801 i += 2;
13802 word++;
13803 } else {
13804 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13805 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
13806 word++;
13807 }
13808 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013809
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013810 /*
13811 * Set 'word' for later use to clear the rest of memory and save
13812 * the expanded mcode size.
13813 */
13814 word *= 2;
13815 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013816
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013817 /*
13818 * Clear the rest of ASC-3550 Internal RAM (8KB).
13819 */
13820 for (; word < ADV_3550_MEMSIZE; word += 2) {
13821 AdvWriteWordAutoIncLram(iop_base, 0);
13822 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013823
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013824 /*
13825 * Verify the microcode checksum.
13826 */
13827 sum = 0;
13828 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013829
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013830 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
13831 sum += AdvReadWordAutoIncLram(iop_base);
13832 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013833
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013834 if (sum != _adv_asc3550_chksum) {
13835 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
13836 return ADV_ERROR;
13837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013838
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013839 /*
13840 * Restore the RISC memory BIOS region.
13841 */
13842 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13843 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13844 bios_mem[i]);
13845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013846
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013847 /*
13848 * Calculate and write the microcode code checksum to the microcode
13849 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
13850 */
13851 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
13852 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
13853 code_sum = 0;
13854 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
13855 for (word = begin_addr; word < end_addr; word += 2) {
13856 code_sum += AdvReadWordAutoIncLram(iop_base);
13857 }
13858 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013859
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013860 /*
13861 * Read and save microcode version and date.
13862 */
13863 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
13864 asc_dvc->cfg->mcode_date);
13865 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
13866 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013867
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013868 /*
13869 * Set the chip type to indicate the ASC3550.
13870 */
13871 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013872
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013873 /*
13874 * If the PCI Configuration Command Register "Parity Error Response
13875 * Control" Bit was clear (0), then set the microcode variable
13876 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
13877 * to ignore DMA parity errors.
13878 */
13879 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
13880 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13881 word |= CONTROL_FLAG_IGNORE_PERR;
13882 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013884
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013885 /*
13886 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
13887 * threshold of 128 bytes. This register is only accessible to the host.
13888 */
13889 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
13890 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013891
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013892 /*
13893 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040013894 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013895 * device reports it is capable of in Inquiry byte 7.
13896 *
13897 * If SCSI Bus Resets have been disabled, then directly set
13898 * SDTR and WDTR from the EEPROM configuration. This will allow
13899 * the BIOS and warm boot to work without a SCSI bus hang on
13900 * the Inquiry caused by host and target mismatched DTR values.
13901 * Without the SCSI Bus Reset, before an Inquiry a device can't
13902 * be assumed to be in Asynchronous, Narrow mode.
13903 */
13904 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
13905 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
13906 asc_dvc->wdtr_able);
13907 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
13908 asc_dvc->sdtr_able);
13909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013910
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013911 /*
13912 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
13913 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
13914 * bitmask. These values determine the maximum SDTR speed negotiated
13915 * with a device.
13916 *
13917 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
13918 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
13919 * without determining here whether the device supports SDTR.
13920 *
13921 * 4-bit speed SDTR speed name
13922 * =========== ===============
13923 * 0000b (0x0) SDTR disabled
13924 * 0001b (0x1) 5 Mhz
13925 * 0010b (0x2) 10 Mhz
13926 * 0011b (0x3) 20 Mhz (Ultra)
13927 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
13928 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
13929 * 0110b (0x6) Undefined
13930 * .
13931 * 1111b (0xF) Undefined
13932 */
13933 word = 0;
13934 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13935 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
13936 /* Set Ultra speed for TID 'tid'. */
13937 word |= (0x3 << (4 * (tid % 4)));
13938 } else {
13939 /* Set Fast speed for TID 'tid'. */
13940 word |= (0x2 << (4 * (tid % 4)));
13941 }
13942 if (tid == 3) { /* Check if done with sdtr_speed1. */
13943 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
13944 word = 0;
13945 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
13946 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
13947 word = 0;
13948 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
13949 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
13950 word = 0;
13951 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
13952 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
13953 /* End of loop. */
13954 }
13955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013956
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013957 /*
13958 * Set microcode operating variable for the disconnect per TID bitmask.
13959 */
13960 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
13961 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013962
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013963 /*
13964 * Set SCSI_CFG0 Microcode Default Value.
13965 *
13966 * The microcode will set the SCSI_CFG0 register using this value
13967 * after it is started below.
13968 */
13969 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
13970 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
13971 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013972
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013973 /*
13974 * Determine SCSI_CFG1 Microcode Default Value.
13975 *
13976 * The microcode will set the SCSI_CFG1 register using this value
13977 * after it is started below.
13978 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013979
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013980 /* Read current SCSI_CFG1 Register value. */
13981 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013982
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013983 /*
13984 * If all three connectors are in use, return an error.
13985 */
13986 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
13987 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
13988 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
13989 return ADV_ERROR;
13990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013991
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013992 /*
13993 * If the internal narrow cable is reversed all of the SCSI_CTRL
13994 * register signals will be set. Check for and return an error if
13995 * this condition is found.
13996 */
13997 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
13998 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
13999 return ADV_ERROR;
14000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014001
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014002 /*
14003 * If this is a differential board and a single-ended device
14004 * is attached to one of the connectors, return an error.
14005 */
14006 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
14007 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
14008 return ADV_ERROR;
14009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014011 /*
14012 * If automatic termination control is enabled, then set the
14013 * termination value based on a table listed in a_condor.h.
14014 *
14015 * If manual termination was specified with an EEPROM setting
14016 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
14017 * is ready to be 'ored' into SCSI_CFG1.
14018 */
14019 if (asc_dvc->cfg->termination == 0) {
14020 /*
14021 * The software always controls termination by setting TERM_CTL_SEL.
14022 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
14023 */
14024 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014025
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014026 switch (scsi_cfg1 & CABLE_DETECT) {
14027 /* TERM_CTL_H: on, TERM_CTL_L: on */
14028 case 0x3:
14029 case 0x7:
14030 case 0xB:
14031 case 0xD:
14032 case 0xE:
14033 case 0xF:
14034 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
14035 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014036
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014037 /* TERM_CTL_H: on, TERM_CTL_L: off */
14038 case 0x1:
14039 case 0x5:
14040 case 0x9:
14041 case 0xA:
14042 case 0xC:
14043 asc_dvc->cfg->termination |= TERM_CTL_H;
14044 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014045
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014046 /* TERM_CTL_H: off, TERM_CTL_L: off */
14047 case 0x2:
14048 case 0x6:
14049 break;
14050 }
14051 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014052
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014053 /*
14054 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
14055 */
14056 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014057
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014058 /*
14059 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
14060 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
14061 * referenced, because the hardware internally inverts
14062 * the Termination High and Low bits if TERM_POL is set.
14063 */
14064 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014065
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014066 /*
14067 * Set SCSI_CFG1 Microcode Default Value
14068 *
14069 * Set filter value and possibly modified termination control
14070 * bits in the Microcode SCSI_CFG1 Register Value.
14071 *
14072 * The microcode will set the SCSI_CFG1 register using this value
14073 * after it is started below.
14074 */
14075 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14076 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014077
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014078 /*
14079 * Set MEM_CFG Microcode Default Value
14080 *
14081 * The microcode will set the MEM_CFG register using this value
14082 * after it is started below.
14083 *
14084 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14085 * are defined.
14086 *
14087 * ASC-3550 has 8KB internal memory.
14088 */
14089 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14090 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014091
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014092 /*
14093 * Set SEL_MASK Microcode Default Value
14094 *
14095 * The microcode will set the SEL_MASK register using this value
14096 * after it is started below.
14097 */
14098 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14099 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014100
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014101 /*
14102 * Build carrier freelist.
14103 *
14104 * Driver must have already allocated memory and set 'carrier_buf'.
14105 */
14106 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014107
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014108 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14109 asc_dvc->carr_freelist = NULL;
14110 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14111 buf_size = ADV_CARRIER_BUFSIZE;
14112 } else {
14113 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014115
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014116 do {
14117 /*
14118 * Get physical address of the carrier 'carrp'.
14119 */
14120 contig_len = sizeof(ADV_CARR_T);
14121 carr_paddr =
14122 cpu_to_le32(DvcGetPhyAddr
14123 (asc_dvc, NULL, (uchar *)carrp,
14124 (ADV_SDCNT *)&contig_len,
14125 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014126
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014127 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014128
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014129 /*
14130 * If the current carrier is not physically contiguous, then
14131 * maybe there was a page crossing. Try the next carrier aligned
14132 * start address.
14133 */
14134 if (contig_len < sizeof(ADV_CARR_T)) {
14135 carrp++;
14136 continue;
14137 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014138
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014139 carrp->carr_pa = carr_paddr;
14140 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014141
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014142 /*
14143 * Insert the carrier at the beginning of the freelist.
14144 */
14145 carrp->next_vpa =
14146 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14147 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014148
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014149 carrp++;
14150 }
14151 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014152
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014153 /*
14154 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14155 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014156
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014157 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14158 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14159 return ADV_ERROR;
14160 }
14161 asc_dvc->carr_freelist = (ADV_CARR_T *)
14162 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014163
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014164 /*
14165 * The first command issued will be placed in the stopper carrier.
14166 */
14167 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014168
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014169 /*
14170 * Set RISC ICQ physical address start value.
14171 */
14172 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014173
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014174 /*
14175 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14176 */
14177 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14178 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14179 return ADV_ERROR;
14180 }
14181 asc_dvc->carr_freelist = (ADV_CARR_T *)
14182 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014183
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014184 /*
14185 * The first command completed by the RISC will be placed in
14186 * the stopper.
14187 *
14188 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14189 * completed the RISC will set the ASC_RQ_STOPPER bit.
14190 */
14191 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014192
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014193 /*
14194 * Set RISC IRQ physical address start value.
14195 */
14196 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14197 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014198
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014199 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14200 (ADV_INTR_ENABLE_HOST_INTR |
14201 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014202
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014203 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14204 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014205
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014206 /* finally, finally, gentlemen, start your engine */
14207 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014208
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014209 /*
14210 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14211 * Resets should be performed. The RISC has to be running
14212 * to issue a SCSI Bus Reset.
14213 */
14214 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14215 /*
14216 * If the BIOS Signature is present in memory, restore the
14217 * BIOS Handshake Configuration Table and do not perform
14218 * a SCSI Bus Reset.
14219 */
14220 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14221 0x55AA) {
14222 /*
14223 * Restore per TID negotiated values.
14224 */
14225 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14226 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14227 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14228 tagqng_able);
14229 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14230 AdvWriteByteLram(iop_base,
14231 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14232 max_cmd[tid]);
14233 }
14234 } else {
14235 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14236 warn_code = ASC_WARN_BUSRESET_ERROR;
14237 }
14238 }
14239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014240
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014241 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014242}
14243
14244/*
14245 * Initialize the ASC-38C0800.
14246 *
14247 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14248 *
14249 * For a non-fatal error return a warning code. If there are no warnings
14250 * then 0 is returned.
14251 *
14252 * Needed after initialization for error recovery.
14253 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014254static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014255{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014256 AdvPortAddr iop_base;
14257 ushort warn_code;
14258 ADV_DCNT sum;
14259 int begin_addr;
14260 int end_addr;
14261 ushort code_sum;
14262 int word;
14263 int j;
14264 int adv_asc38C0800_expanded_size;
14265 ADV_CARR_T *carrp;
14266 ADV_DCNT contig_len;
14267 ADV_SDCNT buf_size;
14268 ADV_PADDR carr_paddr;
14269 int i;
14270 ushort scsi_cfg1;
14271 uchar byte;
14272 uchar tid;
14273 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14274 ushort wdtr_able, sdtr_able, tagqng_able;
14275 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014276
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014277 /* If there is already an error, don't continue. */
14278 if (asc_dvc->err_code != 0) {
14279 return ADV_ERROR;
14280 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014281
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014282 /*
14283 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14284 */
14285 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14286 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14287 return ADV_ERROR;
14288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014289
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014290 warn_code = 0;
14291 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014292
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014293 /*
14294 * Save the RISC memory BIOS region before writing the microcode.
14295 * The BIOS may already be loaded and using its RISC LRAM region
14296 * so its region must be saved and restored.
14297 *
14298 * Note: This code makes the assumption, which is currently true,
14299 * that a chip reset does not clear RISC LRAM.
14300 */
14301 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14302 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14303 bios_mem[i]);
14304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014306 /*
14307 * Save current per TID negotiated values.
14308 */
14309 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14310 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14311 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14312 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14313 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14314 max_cmd[tid]);
14315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014316
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014317 /*
14318 * RAM BIST (RAM Built-In Self Test)
14319 *
14320 * Address : I/O base + offset 0x38h register (byte).
14321 * Function: Bit 7-6(RW) : RAM mode
14322 * Normal Mode : 0x00
14323 * Pre-test Mode : 0x40
14324 * RAM Test Mode : 0x80
14325 * Bit 5 : unused
14326 * Bit 4(RO) : Done bit
14327 * Bit 3-0(RO) : Status
14328 * Host Error : 0x08
14329 * Int_RAM Error : 0x04
14330 * RISC Error : 0x02
14331 * SCSI Error : 0x01
14332 * No Error : 0x00
14333 *
14334 * Note: RAM BIST code should be put right here, before loading the
14335 * microcode and after saving the RISC memory BIOS region.
14336 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014337
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014338 /*
14339 * LRAM Pre-test
14340 *
14341 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14342 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14343 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14344 * to NORMAL_MODE, return an error too.
14345 */
14346 for (i = 0; i < 2; i++) {
14347 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14348 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14349 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14350 if ((byte & RAM_TEST_DONE) == 0
14351 || (byte & 0x0F) != PRE_TEST_VALUE) {
14352 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14353 return ADV_ERROR;
14354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014355
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014356 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14357 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14358 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14359 != NORMAL_VALUE) {
14360 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14361 return ADV_ERROR;
14362 }
14363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014364
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014365 /*
14366 * LRAM Test - It takes about 1.5 ms to run through the test.
14367 *
14368 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14369 * If Done bit not set or Status not 0, save register byte, set the
14370 * err_code, and return an error.
14371 */
14372 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14373 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014374
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014375 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14376 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14377 /* Get here if Done bit not set or Status not 0. */
14378 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14379 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14380 return ADV_ERROR;
14381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014383 /* We need to reset back to normal mode after LRAM test passes. */
14384 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014386 /*
14387 * Load the Microcode
14388 *
14389 * Write the microcode image to RISC memory starting at address 0.
14390 *
14391 */
14392 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014393
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014394 /* Assume the following compressed format of the microcode buffer:
14395 *
14396 * 254 word (508 byte) table indexed by byte code followed
14397 * by the following byte codes:
14398 *
14399 * 1-Byte Code:
14400 * 00: Emit word 0 in table.
14401 * 01: Emit word 1 in table.
14402 * .
14403 * FD: Emit word 253 in table.
14404 *
14405 * Multi-Byte Code:
14406 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14407 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14408 */
14409 word = 0;
14410 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
14411 if (_adv_asc38C0800_buf[i] == 0xff) {
14412 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
14413 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14414 _adv_asc38C0800_buf
14415 [i +
14416 3] << 8) |
14417 _adv_asc38C0800_buf
14418 [i + 2]));
14419 word++;
14420 }
14421 i += 3;
14422 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
14423 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14424 _adv_asc38C0800_buf
14425 [i +
14426 2] << 8) |
14427 _adv_asc38C0800_buf[i
14428 +
14429 1]));
14430 i += 2;
14431 word++;
14432 } else {
14433 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14434 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
14435 word++;
14436 }
14437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014438
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014439 /*
14440 * Set 'word' for later use to clear the rest of memory and save
14441 * the expanded mcode size.
14442 */
14443 word *= 2;
14444 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014445
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014446 /*
14447 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
14448 */
14449 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
14450 AdvWriteWordAutoIncLram(iop_base, 0);
14451 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014452
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014453 /*
14454 * Verify the microcode checksum.
14455 */
14456 sum = 0;
14457 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014458
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014459 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
14460 sum += AdvReadWordAutoIncLram(iop_base);
14461 }
14462 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014463
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014464 ASC_DBG2(1,
14465 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
14466 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014467
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014468 if (sum != _adv_asc38C0800_chksum) {
14469 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14470 return ADV_ERROR;
14471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014473 /*
14474 * Restore the RISC memory BIOS region.
14475 */
14476 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14477 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14478 bios_mem[i]);
14479 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014481 /*
14482 * Calculate and write the microcode code checksum to the microcode
14483 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14484 */
14485 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14486 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14487 code_sum = 0;
14488 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14489 for (word = begin_addr; word < end_addr; word += 2) {
14490 code_sum += AdvReadWordAutoIncLram(iop_base);
14491 }
14492 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014494 /*
14495 * Read microcode version and date.
14496 */
14497 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14498 asc_dvc->cfg->mcode_date);
14499 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14500 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014501
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014502 /*
14503 * Set the chip type to indicate the ASC38C0800.
14504 */
14505 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014506
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014507 /*
14508 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
14509 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
14510 * cable detection and then we are able to read C_DET[3:0].
14511 *
14512 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
14513 * Microcode Default Value' section below.
14514 */
14515 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
14516 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
14517 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014518
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014519 /*
14520 * If the PCI Configuration Command Register "Parity Error Response
14521 * Control" Bit was clear (0), then set the microcode variable
14522 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14523 * to ignore DMA parity errors.
14524 */
14525 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14526 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14527 word |= CONTROL_FLAG_IGNORE_PERR;
14528 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14529 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014530
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014531 /*
14532 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
14533 * bits for the default FIFO threshold.
14534 *
14535 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
14536 *
14537 * For DMA Errata #4 set the BC_THRESH_ENB bit.
14538 */
14539 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14540 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
14541 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014542
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014543 /*
14544 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040014545 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014546 * device reports it is capable of in Inquiry byte 7.
14547 *
14548 * If SCSI Bus Resets have been disabled, then directly set
14549 * SDTR and WDTR from the EEPROM configuration. This will allow
14550 * the BIOS and warm boot to work without a SCSI bus hang on
14551 * the Inquiry caused by host and target mismatched DTR values.
14552 * Without the SCSI Bus Reset, before an Inquiry a device can't
14553 * be assumed to be in Asynchronous, Narrow mode.
14554 */
14555 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14556 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14557 asc_dvc->wdtr_able);
14558 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14559 asc_dvc->sdtr_able);
14560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014561
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014562 /*
14563 * Set microcode operating variables for DISC and SDTR_SPEED1,
14564 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
14565 * configuration values.
14566 *
14567 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14568 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14569 * without determining here whether the device supports SDTR.
14570 */
14571 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14572 asc_dvc->cfg->disc_enable);
14573 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
14574 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
14575 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
14576 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014577
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014578 /*
14579 * Set SCSI_CFG0 Microcode Default Value.
14580 *
14581 * The microcode will set the SCSI_CFG0 register using this value
14582 * after it is started below.
14583 */
14584 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14585 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14586 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014587
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014588 /*
14589 * Determine SCSI_CFG1 Microcode Default Value.
14590 *
14591 * The microcode will set the SCSI_CFG1 register using this value
14592 * after it is started below.
14593 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014594
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014595 /* Read current SCSI_CFG1 Register value. */
14596 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014597
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014598 /*
14599 * If the internal narrow cable is reversed all of the SCSI_CTRL
14600 * register signals will be set. Check for and return an error if
14601 * this condition is found.
14602 */
14603 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14604 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14605 return ADV_ERROR;
14606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014607
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014608 /*
14609 * All kind of combinations of devices attached to one of four connectors
14610 * are acceptable except HVD device attached. For example, LVD device can
14611 * be attached to SE connector while SE device attached to LVD connector.
14612 * If LVD device attached to SE connector, it only runs up to Ultra speed.
14613 *
14614 * If an HVD device is attached to one of LVD connectors, return an error.
14615 * However, there is no way to detect HVD device attached to SE connectors.
14616 */
14617 if (scsi_cfg1 & HVD) {
14618 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
14619 return ADV_ERROR;
14620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014621
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014622 /*
14623 * If either SE or LVD automatic termination control is enabled, then
14624 * set the termination value based on a table listed in a_condor.h.
14625 *
14626 * If manual termination was specified with an EEPROM setting then
14627 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
14628 * be 'ored' into SCSI_CFG1.
14629 */
14630 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
14631 /* SE automatic termination control is enabled. */
14632 switch (scsi_cfg1 & C_DET_SE) {
14633 /* TERM_SE_HI: on, TERM_SE_LO: on */
14634 case 0x1:
14635 case 0x2:
14636 case 0x3:
14637 asc_dvc->cfg->termination |= TERM_SE;
14638 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014639
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014640 /* TERM_SE_HI: on, TERM_SE_LO: off */
14641 case 0x0:
14642 asc_dvc->cfg->termination |= TERM_SE_HI;
14643 break;
14644 }
14645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014646
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014647 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
14648 /* LVD automatic termination control is enabled. */
14649 switch (scsi_cfg1 & C_DET_LVD) {
14650 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
14651 case 0x4:
14652 case 0x8:
14653 case 0xC:
14654 asc_dvc->cfg->termination |= TERM_LVD;
14655 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014657 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
14658 case 0x0:
14659 break;
14660 }
14661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014662
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014663 /*
14664 * Clear any set TERM_SE and TERM_LVD bits.
14665 */
14666 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014667
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014668 /*
14669 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
14670 */
14671 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014672
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014673 /*
14674 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
14675 * and set possibly modified termination control bits in the Microcode
14676 * SCSI_CFG1 Register Value.
14677 */
14678 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014679
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014680 /*
14681 * Set SCSI_CFG1 Microcode Default Value
14682 *
14683 * Set possibly modified termination control and reset DIS_TERM_DRV
14684 * bits in the Microcode SCSI_CFG1 Register Value.
14685 *
14686 * The microcode will set the SCSI_CFG1 register using this value
14687 * after it is started below.
14688 */
14689 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014690
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014691 /*
14692 * Set MEM_CFG Microcode Default Value
14693 *
14694 * The microcode will set the MEM_CFG register using this value
14695 * after it is started below.
14696 *
14697 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14698 * are defined.
14699 *
14700 * ASC-38C0800 has 16KB internal memory.
14701 */
14702 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14703 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014704
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014705 /*
14706 * Set SEL_MASK Microcode Default Value
14707 *
14708 * The microcode will set the SEL_MASK register using this value
14709 * after it is started below.
14710 */
14711 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14712 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014713
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014714 /*
14715 * Build the carrier freelist.
14716 *
14717 * Driver must have already allocated memory and set 'carrier_buf'.
14718 */
14719 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014720
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014721 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14722 asc_dvc->carr_freelist = NULL;
14723 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14724 buf_size = ADV_CARRIER_BUFSIZE;
14725 } else {
14726 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014728
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014729 do {
14730 /*
14731 * Get physical address for the carrier 'carrp'.
14732 */
14733 contig_len = sizeof(ADV_CARR_T);
14734 carr_paddr =
14735 cpu_to_le32(DvcGetPhyAddr
14736 (asc_dvc, NULL, (uchar *)carrp,
14737 (ADV_SDCNT *)&contig_len,
14738 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014739
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014740 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014741
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014742 /*
14743 * If the current carrier is not physically contiguous, then
14744 * maybe there was a page crossing. Try the next carrier aligned
14745 * start address.
14746 */
14747 if (contig_len < sizeof(ADV_CARR_T)) {
14748 carrp++;
14749 continue;
14750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014751
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014752 carrp->carr_pa = carr_paddr;
14753 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014754
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014755 /*
14756 * Insert the carrier at the beginning of the freelist.
14757 */
14758 carrp->next_vpa =
14759 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14760 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014761
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014762 carrp++;
14763 }
14764 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014765
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014766 /*
14767 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14768 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014770 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14771 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14772 return ADV_ERROR;
14773 }
14774 asc_dvc->carr_freelist = (ADV_CARR_T *)
14775 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014776
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014777 /*
14778 * The first command issued will be placed in the stopper carrier.
14779 */
14780 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014781
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014782 /*
14783 * Set RISC ICQ physical address start value.
14784 * carr_pa is LE, must be native before write
14785 */
14786 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014787
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014788 /*
14789 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14790 */
14791 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14792 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14793 return ADV_ERROR;
14794 }
14795 asc_dvc->carr_freelist = (ADV_CARR_T *)
14796 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014797
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014798 /*
14799 * The first command completed by the RISC will be placed in
14800 * the stopper.
14801 *
14802 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14803 * completed the RISC will set the ASC_RQ_STOPPER bit.
14804 */
14805 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014807 /*
14808 * Set RISC IRQ physical address start value.
14809 *
14810 * carr_pa is LE, must be native before write *
14811 */
14812 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14813 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014814
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014815 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14816 (ADV_INTR_ENABLE_HOST_INTR |
14817 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014818
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014819 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14820 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014821
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014822 /* finally, finally, gentlemen, start your engine */
14823 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014824
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014825 /*
14826 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14827 * Resets should be performed. The RISC has to be running
14828 * to issue a SCSI Bus Reset.
14829 */
14830 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14831 /*
14832 * If the BIOS Signature is present in memory, restore the
14833 * BIOS Handshake Configuration Table and do not perform
14834 * a SCSI Bus Reset.
14835 */
14836 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14837 0x55AA) {
14838 /*
14839 * Restore per TID negotiated values.
14840 */
14841 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14842 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14843 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14844 tagqng_able);
14845 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14846 AdvWriteByteLram(iop_base,
14847 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14848 max_cmd[tid]);
14849 }
14850 } else {
14851 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14852 warn_code = ASC_WARN_BUSRESET_ERROR;
14853 }
14854 }
14855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014856
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014857 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014858}
14859
14860/*
14861 * Initialize the ASC-38C1600.
14862 *
14863 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
14864 *
14865 * For a non-fatal error return a warning code. If there are no warnings
14866 * then 0 is returned.
14867 *
14868 * Needed after initialization for error recovery.
14869 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014870static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014871{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014872 AdvPortAddr iop_base;
14873 ushort warn_code;
14874 ADV_DCNT sum;
14875 int begin_addr;
14876 int end_addr;
14877 ushort code_sum;
14878 long word;
14879 int j;
14880 int adv_asc38C1600_expanded_size;
14881 ADV_CARR_T *carrp;
14882 ADV_DCNT contig_len;
14883 ADV_SDCNT buf_size;
14884 ADV_PADDR carr_paddr;
14885 int i;
14886 ushort scsi_cfg1;
14887 uchar byte;
14888 uchar tid;
14889 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14890 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
14891 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014892
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014893 /* If there is already an error, don't continue. */
14894 if (asc_dvc->err_code != 0) {
14895 return ADV_ERROR;
14896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014897
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014898 /*
14899 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
14900 */
14901 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
14902 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14903 return ADV_ERROR;
14904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014905
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014906 warn_code = 0;
14907 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014908
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014909 /*
14910 * Save the RISC memory BIOS region before writing the microcode.
14911 * The BIOS may already be loaded and using its RISC LRAM region
14912 * so its region must be saved and restored.
14913 *
14914 * Note: This code makes the assumption, which is currently true,
14915 * that a chip reset does not clear RISC LRAM.
14916 */
14917 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14918 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14919 bios_mem[i]);
14920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014921
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014922 /*
14923 * Save current per TID negotiated values.
14924 */
14925 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14926 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14927 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
14928 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14929 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
14930 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14931 max_cmd[tid]);
14932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014933
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014934 /*
14935 * RAM BIST (Built-In Self Test)
14936 *
14937 * Address : I/O base + offset 0x38h register (byte).
14938 * Function: Bit 7-6(RW) : RAM mode
14939 * Normal Mode : 0x00
14940 * Pre-test Mode : 0x40
14941 * RAM Test Mode : 0x80
14942 * Bit 5 : unused
14943 * Bit 4(RO) : Done bit
14944 * Bit 3-0(RO) : Status
14945 * Host Error : 0x08
14946 * Int_RAM Error : 0x04
14947 * RISC Error : 0x02
14948 * SCSI Error : 0x01
14949 * No Error : 0x00
14950 *
14951 * Note: RAM BIST code should be put right here, before loading the
14952 * microcode and after saving the RISC memory BIOS region.
14953 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014954
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014955 /*
14956 * LRAM Pre-test
14957 *
14958 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14959 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14960 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14961 * to NORMAL_MODE, return an error too.
14962 */
14963 for (i = 0; i < 2; i++) {
14964 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14965 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14966 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14967 if ((byte & RAM_TEST_DONE) == 0
14968 || (byte & 0x0F) != PRE_TEST_VALUE) {
14969 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14970 return ADV_ERROR;
14971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014972
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014973 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14974 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14975 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14976 != NORMAL_VALUE) {
14977 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14978 return ADV_ERROR;
14979 }
14980 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014981
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014982 /*
14983 * LRAM Test - It takes about 1.5 ms to run through the test.
14984 *
14985 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14986 * If Done bit not set or Status not 0, save register byte, set the
14987 * err_code, and return an error.
14988 */
14989 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14990 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014991
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014992 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14993 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14994 /* Get here if Done bit not set or Status not 0. */
14995 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14996 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14997 return ADV_ERROR;
14998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014999
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015000 /* We need to reset back to normal mode after LRAM test passes. */
15001 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015002
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015003 /*
15004 * Load the Microcode
15005 *
15006 * Write the microcode image to RISC memory starting at address 0.
15007 *
15008 */
15009 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015011 /*
15012 * Assume the following compressed format of the microcode buffer:
15013 *
15014 * 254 word (508 byte) table indexed by byte code followed
15015 * by the following byte codes:
15016 *
15017 * 1-Byte Code:
15018 * 00: Emit word 0 in table.
15019 * 01: Emit word 1 in table.
15020 * .
15021 * FD: Emit word 253 in table.
15022 *
15023 * Multi-Byte Code:
15024 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15025 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15026 */
15027 word = 0;
15028 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
15029 if (_adv_asc38C1600_buf[i] == 0xff) {
15030 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
15031 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15032 _adv_asc38C1600_buf
15033 [i +
15034 3] << 8) |
15035 _adv_asc38C1600_buf
15036 [i + 2]));
15037 word++;
15038 }
15039 i += 3;
15040 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
15041 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15042 _adv_asc38C1600_buf
15043 [i +
15044 2] << 8) |
15045 _adv_asc38C1600_buf[i
15046 +
15047 1]));
15048 i += 2;
15049 word++;
15050 } else {
15051 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15052 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
15053 word++;
15054 }
15055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015056
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015057 /*
15058 * Set 'word' for later use to clear the rest of memory and save
15059 * the expanded mcode size.
15060 */
15061 word *= 2;
15062 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015063
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015064 /*
15065 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15066 */
15067 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15068 AdvWriteWordAutoIncLram(iop_base, 0);
15069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015070
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015071 /*
15072 * Verify the microcode checksum.
15073 */
15074 sum = 0;
15075 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015076
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015077 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15078 sum += AdvReadWordAutoIncLram(iop_base);
15079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015080
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015081 if (sum != _adv_asc38C1600_chksum) {
15082 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15083 return ADV_ERROR;
15084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015085
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015086 /*
15087 * Restore the RISC memory BIOS region.
15088 */
15089 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15090 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15091 bios_mem[i]);
15092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015094 /*
15095 * Calculate and write the microcode code checksum to the microcode
15096 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15097 */
15098 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15099 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15100 code_sum = 0;
15101 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15102 for (word = begin_addr; word < end_addr; word += 2) {
15103 code_sum += AdvReadWordAutoIncLram(iop_base);
15104 }
15105 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015106
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015107 /*
15108 * Read microcode version and date.
15109 */
15110 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15111 asc_dvc->cfg->mcode_date);
15112 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15113 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015114
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015115 /*
15116 * Set the chip type to indicate the ASC38C1600.
15117 */
15118 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015119
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015120 /*
15121 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15122 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15123 * cable detection and then we are able to read C_DET[3:0].
15124 *
15125 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15126 * Microcode Default Value' section below.
15127 */
15128 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15129 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15130 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015131
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015132 /*
15133 * If the PCI Configuration Command Register "Parity Error Response
15134 * Control" Bit was clear (0), then set the microcode variable
15135 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15136 * to ignore DMA parity errors.
15137 */
15138 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15139 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15140 word |= CONTROL_FLAG_IGNORE_PERR;
15141 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015143
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015144 /*
15145 * If the BIOS control flag AIPP (Asynchronous Information
15146 * Phase Protection) disable bit is not set, then set the firmware
15147 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15148 * AIPP checking and encoding.
15149 */
15150 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15151 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15152 word |= CONTROL_FLAG_ENABLE_AIPP;
15153 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015155
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015156 /*
15157 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15158 * and START_CTL_TH [3:2].
15159 */
15160 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15161 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015162
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015163 /*
15164 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040015165 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015166 * device reports it is capable of in Inquiry byte 7.
15167 *
15168 * If SCSI Bus Resets have been disabled, then directly set
15169 * SDTR and WDTR from the EEPROM configuration. This will allow
15170 * the BIOS and warm boot to work without a SCSI bus hang on
15171 * the Inquiry caused by host and target mismatched DTR values.
15172 * Without the SCSI Bus Reset, before an Inquiry a device can't
15173 * be assumed to be in Asynchronous, Narrow mode.
15174 */
15175 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15176 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15177 asc_dvc->wdtr_able);
15178 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15179 asc_dvc->sdtr_able);
15180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015181
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015182 /*
15183 * Set microcode operating variables for DISC and SDTR_SPEED1,
15184 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15185 * configuration values.
15186 *
15187 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15188 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15189 * without determining here whether the device supports SDTR.
15190 */
15191 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15192 asc_dvc->cfg->disc_enable);
15193 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15194 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15195 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15196 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015197
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015198 /*
15199 * Set SCSI_CFG0 Microcode Default Value.
15200 *
15201 * The microcode will set the SCSI_CFG0 register using this value
15202 * after it is started below.
15203 */
15204 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15205 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15206 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015207
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015208 /*
15209 * Calculate SCSI_CFG1 Microcode Default Value.
15210 *
15211 * The microcode will set the SCSI_CFG1 register using this value
15212 * after it is started below.
15213 *
15214 * Each ASC-38C1600 function has only two cable detect bits.
15215 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15216 */
15217 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015218
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015219 /*
15220 * If the cable is reversed all of the SCSI_CTRL register signals
15221 * will be set. Check for and return an error if this condition is
15222 * found.
15223 */
15224 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15225 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15226 return ADV_ERROR;
15227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015228
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015229 /*
15230 * Each ASC-38C1600 function has two connectors. Only an HVD device
15231 * can not be connected to either connector. An LVD device or SE device
15232 * may be connected to either connecor. If an SE device is connected,
15233 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15234 *
15235 * If an HVD device is attached, return an error.
15236 */
15237 if (scsi_cfg1 & HVD) {
15238 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15239 return ADV_ERROR;
15240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015241
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015242 /*
15243 * Each function in the ASC-38C1600 uses only the SE cable detect and
15244 * termination because there are two connectors for each function. Each
15245 * function may use either LVD or SE mode. Corresponding the SE automatic
15246 * termination control EEPROM bits are used for each function. Each
15247 * function has its own EEPROM. If SE automatic control is enabled for
15248 * the function, then set the termination value based on a table listed
15249 * in a_condor.h.
15250 *
15251 * If manual termination is specified in the EEPROM for the function,
15252 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15253 * ready to be 'ored' into SCSI_CFG1.
15254 */
15255 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15256 /* SE automatic termination control is enabled. */
15257 switch (scsi_cfg1 & C_DET_SE) {
15258 /* TERM_SE_HI: on, TERM_SE_LO: on */
15259 case 0x1:
15260 case 0x2:
15261 case 0x3:
15262 asc_dvc->cfg->termination |= TERM_SE;
15263 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015264
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015265 case 0x0:
15266 if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
15267 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15268 } else {
15269 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15270 asc_dvc->cfg->termination |= TERM_SE_HI;
15271 }
15272 break;
15273 }
15274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015275
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015276 /*
15277 * Clear any set TERM_SE bits.
15278 */
15279 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015280
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015281 /*
15282 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15283 */
15284 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015285
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015286 /*
15287 * Clear Big Endian and Terminator Polarity bits and set possibly
15288 * modified termination control bits in the Microcode SCSI_CFG1
15289 * Register Value.
15290 *
15291 * Big Endian bit is not used even on big endian machines.
15292 */
15293 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015294
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015295 /*
15296 * Set SCSI_CFG1 Microcode Default Value
15297 *
15298 * Set possibly modified termination control bits in the Microcode
15299 * SCSI_CFG1 Register Value.
15300 *
15301 * The microcode will set the SCSI_CFG1 register using this value
15302 * after it is started below.
15303 */
15304 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015306 /*
15307 * Set MEM_CFG Microcode Default Value
15308 *
15309 * The microcode will set the MEM_CFG register using this value
15310 * after it is started below.
15311 *
15312 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15313 * are defined.
15314 *
15315 * ASC-38C1600 has 32KB internal memory.
15316 *
15317 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15318 * out a special 16K Adv Library and Microcode version. After the issue
15319 * resolved, we should turn back to the 32K support. Both a_condor.h and
15320 * mcode.sas files also need to be updated.
15321 *
15322 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15323 * BIOS_EN | RAM_SZ_32KB);
15324 */
15325 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15326 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015327
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015328 /*
15329 * Set SEL_MASK Microcode Default Value
15330 *
15331 * The microcode will set the SEL_MASK register using this value
15332 * after it is started below.
15333 */
15334 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15335 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015336
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015337 /*
15338 * Build the carrier freelist.
15339 *
15340 * Driver must have already allocated memory and set 'carrier_buf'.
15341 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015342
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015343 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015344
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015345 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15346 asc_dvc->carr_freelist = NULL;
15347 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15348 buf_size = ADV_CARRIER_BUFSIZE;
15349 } else {
15350 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015352
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015353 do {
15354 /*
15355 * Get physical address for the carrier 'carrp'.
15356 */
15357 contig_len = sizeof(ADV_CARR_T);
15358 carr_paddr =
15359 cpu_to_le32(DvcGetPhyAddr
15360 (asc_dvc, NULL, (uchar *)carrp,
15361 (ADV_SDCNT *)&contig_len,
15362 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015363
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015364 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015365
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015366 /*
15367 * If the current carrier is not physically contiguous, then
15368 * maybe there was a page crossing. Try the next carrier aligned
15369 * start address.
15370 */
15371 if (contig_len < sizeof(ADV_CARR_T)) {
15372 carrp++;
15373 continue;
15374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015375
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015376 carrp->carr_pa = carr_paddr;
15377 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015378
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015379 /*
15380 * Insert the carrier at the beginning of the freelist.
15381 */
15382 carrp->next_vpa =
15383 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15384 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015386 carrp++;
15387 }
15388 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015389
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015390 /*
15391 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15392 */
15393 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15394 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15395 return ADV_ERROR;
15396 }
15397 asc_dvc->carr_freelist = (ADV_CARR_T *)
15398 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015399
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015400 /*
15401 * The first command issued will be placed in the stopper carrier.
15402 */
15403 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015404
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015405 /*
15406 * Set RISC ICQ physical address start value. Initialize the
15407 * COMMA register to the same value otherwise the RISC will
15408 * prematurely detect a command is available.
15409 */
15410 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
15411 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
15412 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015413
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015414 /*
15415 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15416 */
15417 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15418 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15419 return ADV_ERROR;
15420 }
15421 asc_dvc->carr_freelist = (ADV_CARR_T *)
15422 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015423
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015424 /*
15425 * The first command completed by the RISC will be placed in
15426 * the stopper.
15427 *
15428 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15429 * completed the RISC will set the ASC_RQ_STOPPER bit.
15430 */
15431 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015432
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015433 /*
15434 * Set RISC IRQ physical address start value.
15435 */
15436 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15437 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015438
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015439 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15440 (ADV_INTR_ENABLE_HOST_INTR |
15441 ADV_INTR_ENABLE_GLOBAL_INTR));
15442 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15443 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015444
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015445 /* finally, finally, gentlemen, start your engine */
15446 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015447
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015448 /*
15449 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15450 * Resets should be performed. The RISC has to be running
15451 * to issue a SCSI Bus Reset.
15452 */
15453 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15454 /*
15455 * If the BIOS Signature is present in memory, restore the
15456 * per TID microcode operating variables.
15457 */
15458 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15459 0x55AA) {
15460 /*
15461 * Restore per TID negotiated values.
15462 */
15463 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15464 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15465 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15466 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15467 tagqng_able);
15468 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15469 AdvWriteByteLram(iop_base,
15470 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15471 max_cmd[tid]);
15472 }
15473 } else {
15474 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15475 warn_code = ASC_WARN_BUSRESET_ERROR;
15476 }
15477 }
15478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015479
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015480 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015481}
15482
15483/*
15484 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15485 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15486 * all of this is done.
15487 *
15488 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15489 *
15490 * For a non-fatal error return a warning code. If there are no warnings
15491 * then 0 is returned.
15492 *
15493 * Note: Chip is stopped on entry.
15494 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015495static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015496{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015497 AdvPortAddr iop_base;
15498 ushort warn_code;
15499 ADVEEP_3550_CONFIG eep_config;
15500 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015501
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015502 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015503
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015504 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015505
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015506 /*
15507 * Read the board's EEPROM configuration.
15508 *
15509 * Set default values if a bad checksum is found.
15510 */
15511 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
15512 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015513
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015514 /*
15515 * Set EEPROM default values.
15516 */
15517 for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
15518 *((uchar *)&eep_config + i) =
15519 *((uchar *)&Default_3550_EEPROM_Config + i);
15520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015521
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015522 /*
15523 * Assume the 6 byte board serial number that was read
15524 * from EEPROM is correct even if the EEPROM checksum
15525 * failed.
15526 */
15527 eep_config.serial_number_word3 =
15528 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015529
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015530 eep_config.serial_number_word2 =
15531 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015532
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015533 eep_config.serial_number_word1 =
15534 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015535
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015536 AdvSet3550EEPConfig(iop_base, &eep_config);
15537 }
15538 /*
15539 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15540 * EEPROM configuration that was read.
15541 *
15542 * This is the mapping of EEPROM fields to Adv Library fields.
15543 */
15544 asc_dvc->wdtr_able = eep_config.wdtr_able;
15545 asc_dvc->sdtr_able = eep_config.sdtr_able;
15546 asc_dvc->ultra_able = eep_config.ultra_able;
15547 asc_dvc->tagqng_able = eep_config.tagqng_able;
15548 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15549 asc_dvc->max_host_qng = eep_config.max_host_qng;
15550 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15551 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15552 asc_dvc->start_motor = eep_config.start_motor;
15553 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15554 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15555 asc_dvc->no_scam = eep_config.scam_tolerant;
15556 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15557 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15558 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015559
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015560 /*
15561 * Set the host maximum queuing (max. 253, min. 16) and the per device
15562 * maximum queuing (max. 63, min. 4).
15563 */
15564 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15565 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15566 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15567 /* If the value is zero, assume it is uninitialized. */
15568 if (eep_config.max_host_qng == 0) {
15569 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15570 } else {
15571 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15572 }
15573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015575 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15576 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15577 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15578 /* If the value is zero, assume it is uninitialized. */
15579 if (eep_config.max_dvc_qng == 0) {
15580 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15581 } else {
15582 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15583 }
15584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015585
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015586 /*
15587 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15588 * set 'max_dvc_qng' to 'max_host_qng'.
15589 */
15590 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15591 eep_config.max_dvc_qng = eep_config.max_host_qng;
15592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015593
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015594 /*
15595 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15596 * values based on possibly adjusted EEPROM values.
15597 */
15598 asc_dvc->max_host_qng = eep_config.max_host_qng;
15599 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015600
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015601 /*
15602 * If the EEPROM 'termination' field is set to automatic (0), then set
15603 * the ADV_DVC_CFG 'termination' field to automatic also.
15604 *
15605 * If the termination is specified with a non-zero 'termination'
15606 * value check that a legal value is set and set the ADV_DVC_CFG
15607 * 'termination' field appropriately.
15608 */
15609 if (eep_config.termination == 0) {
15610 asc_dvc->cfg->termination = 0; /* auto termination */
15611 } else {
15612 /* Enable manual control with low off / high off. */
15613 if (eep_config.termination == 1) {
15614 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015615
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015616 /* Enable manual control with low off / high on. */
15617 } else if (eep_config.termination == 2) {
15618 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015619
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015620 /* Enable manual control with low on / high on. */
15621 } else if (eep_config.termination == 3) {
15622 asc_dvc->cfg->termination =
15623 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
15624 } else {
15625 /*
15626 * The EEPROM 'termination' field contains a bad value. Use
15627 * automatic termination instead.
15628 */
15629 asc_dvc->cfg->termination = 0;
15630 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15631 }
15632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015633
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015634 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015635}
15636
15637/*
15638 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15639 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15640 * all of this is done.
15641 *
15642 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15643 *
15644 * For a non-fatal error return a warning code. If there are no warnings
15645 * then 0 is returned.
15646 *
15647 * Note: Chip is stopped on entry.
15648 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015649static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015650{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015651 AdvPortAddr iop_base;
15652 ushort warn_code;
15653 ADVEEP_38C0800_CONFIG eep_config;
15654 int i;
15655 uchar tid, termination;
15656 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015657
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015658 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015659
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015660 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015661
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015662 /*
15663 * Read the board's EEPROM configuration.
15664 *
15665 * Set default values if a bad checksum is found.
15666 */
15667 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
15668 eep_config.check_sum) {
15669 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015670
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015671 /*
15672 * Set EEPROM default values.
15673 */
15674 for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
15675 *((uchar *)&eep_config + i) =
15676 *((uchar *)&Default_38C0800_EEPROM_Config + i);
15677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015678
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015679 /*
15680 * Assume the 6 byte board serial number that was read
15681 * from EEPROM is correct even if the EEPROM checksum
15682 * failed.
15683 */
15684 eep_config.serial_number_word3 =
15685 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015686
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015687 eep_config.serial_number_word2 =
15688 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015689
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015690 eep_config.serial_number_word1 =
15691 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015692
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015693 AdvSet38C0800EEPConfig(iop_base, &eep_config);
15694 }
15695 /*
15696 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
15697 * EEPROM configuration that was read.
15698 *
15699 * This is the mapping of EEPROM fields to Adv Library fields.
15700 */
15701 asc_dvc->wdtr_able = eep_config.wdtr_able;
15702 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15703 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15704 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15705 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15706 asc_dvc->tagqng_able = eep_config.tagqng_able;
15707 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15708 asc_dvc->max_host_qng = eep_config.max_host_qng;
15709 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15710 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15711 asc_dvc->start_motor = eep_config.start_motor;
15712 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15713 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15714 asc_dvc->no_scam = eep_config.scam_tolerant;
15715 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15716 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15717 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015718
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015719 /*
15720 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15721 * are set, then set an 'sdtr_able' bit for it.
15722 */
15723 asc_dvc->sdtr_able = 0;
15724 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15725 if (tid == 0) {
15726 sdtr_speed = asc_dvc->sdtr_speed1;
15727 } else if (tid == 4) {
15728 sdtr_speed = asc_dvc->sdtr_speed2;
15729 } else if (tid == 8) {
15730 sdtr_speed = asc_dvc->sdtr_speed3;
15731 } else if (tid == 12) {
15732 sdtr_speed = asc_dvc->sdtr_speed4;
15733 }
15734 if (sdtr_speed & ADV_MAX_TID) {
15735 asc_dvc->sdtr_able |= (1 << tid);
15736 }
15737 sdtr_speed >>= 4;
15738 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015739
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015740 /*
15741 * Set the host maximum queuing (max. 253, min. 16) and the per device
15742 * maximum queuing (max. 63, min. 4).
15743 */
15744 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15745 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15746 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15747 /* If the value is zero, assume it is uninitialized. */
15748 if (eep_config.max_host_qng == 0) {
15749 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15750 } else {
15751 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15752 }
15753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015754
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015755 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15756 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15757 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15758 /* If the value is zero, assume it is uninitialized. */
15759 if (eep_config.max_dvc_qng == 0) {
15760 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15761 } else {
15762 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15763 }
15764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015765
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015766 /*
15767 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15768 * set 'max_dvc_qng' to 'max_host_qng'.
15769 */
15770 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15771 eep_config.max_dvc_qng = eep_config.max_host_qng;
15772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015773
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015774 /*
15775 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15776 * values based on possibly adjusted EEPROM values.
15777 */
15778 asc_dvc->max_host_qng = eep_config.max_host_qng;
15779 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015781 /*
15782 * If the EEPROM 'termination' field is set to automatic (0), then set
15783 * the ADV_DVC_CFG 'termination' field to automatic also.
15784 *
15785 * If the termination is specified with a non-zero 'termination'
15786 * value check that a legal value is set and set the ADV_DVC_CFG
15787 * 'termination' field appropriately.
15788 */
15789 if (eep_config.termination_se == 0) {
15790 termination = 0; /* auto termination for SE */
15791 } else {
15792 /* Enable manual control with low off / high off. */
15793 if (eep_config.termination_se == 1) {
15794 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015795
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015796 /* Enable manual control with low off / high on. */
15797 } else if (eep_config.termination_se == 2) {
15798 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015799
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015800 /* Enable manual control with low on / high on. */
15801 } else if (eep_config.termination_se == 3) {
15802 termination = TERM_SE;
15803 } else {
15804 /*
15805 * The EEPROM 'termination_se' field contains a bad value.
15806 * Use automatic termination instead.
15807 */
15808 termination = 0;
15809 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15810 }
15811 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015812
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015813 if (eep_config.termination_lvd == 0) {
15814 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
15815 } else {
15816 /* Enable manual control with low off / high off. */
15817 if (eep_config.termination_lvd == 1) {
15818 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015819
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015820 /* Enable manual control with low off / high on. */
15821 } else if (eep_config.termination_lvd == 2) {
15822 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015823
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015824 /* Enable manual control with low on / high on. */
15825 } else if (eep_config.termination_lvd == 3) {
15826 asc_dvc->cfg->termination = termination | TERM_LVD;
15827 } else {
15828 /*
15829 * The EEPROM 'termination_lvd' field contains a bad value.
15830 * Use automatic termination instead.
15831 */
15832 asc_dvc->cfg->termination = termination;
15833 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15834 }
15835 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015837 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015838}
15839
15840/*
15841 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
15842 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
15843 * all of this is done.
15844 *
15845 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15846 *
15847 * For a non-fatal error return a warning code. If there are no warnings
15848 * then 0 is returned.
15849 *
15850 * Note: Chip is stopped on entry.
15851 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015852static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015853{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015854 AdvPortAddr iop_base;
15855 ushort warn_code;
15856 ADVEEP_38C1600_CONFIG eep_config;
15857 int i;
15858 uchar tid, termination;
15859 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015860
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015861 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015862
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015863 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015864
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015865 /*
15866 * Read the board's EEPROM configuration.
15867 *
15868 * Set default values if a bad checksum is found.
15869 */
15870 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
15871 eep_config.check_sum) {
15872 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015873
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015874 /*
15875 * Set EEPROM default values.
15876 */
15877 for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
15878 if (i == 1
15879 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
15880 0) {
15881 /*
15882 * Set Function 1 EEPROM Word 0 MSB
15883 *
15884 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
15885 * EEPROM bits.
15886 *
15887 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
15888 * old Mac system booting problem. The Expansion ROM must
15889 * be disabled in Function 1 for these systems.
15890 *
15891 */
15892 *((uchar *)&eep_config + i) =
15893 ((*
15894 ((uchar *)&Default_38C1600_EEPROM_Config
15895 +
15896 i)) &
15897 (~
15898 (((ADV_EEPROM_BIOS_ENABLE |
15899 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015900
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015901 /*
15902 * Set the INTAB (bit 11) if the GPIO 0 input indicates
15903 * the Function 1 interrupt line is wired to INTA.
15904 *
15905 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
15906 * 1 - Function 1 interrupt line wired to INT A.
15907 * 0 - Function 1 interrupt line wired to INT B.
15908 *
15909 * Note: Adapter boards always have Function 0 wired to INTA.
15910 * Put all 5 GPIO bits in input mode and then read
15911 * their input values.
15912 */
15913 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
15914 0);
15915 if (AdvReadByteRegister
15916 (iop_base, IOPB_GPIO_DATA) & 0x01) {
15917 /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
15918 *((uchar *)&eep_config + i) |=
15919 ((ADV_EEPROM_INTAB >> 8) & 0xFF);
15920 }
15921 } else {
15922 *((uchar *)&eep_config + i) =
15923 *((uchar *)&Default_38C1600_EEPROM_Config
15924 + i);
15925 }
15926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015927
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015928 /*
15929 * Assume the 6 byte board serial number that was read
15930 * from EEPROM is correct even if the EEPROM checksum
15931 * failed.
15932 */
15933 eep_config.serial_number_word3 =
15934 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015935
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015936 eep_config.serial_number_word2 =
15937 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015938
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015939 eep_config.serial_number_word1 =
15940 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015941
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015942 AdvSet38C1600EEPConfig(iop_base, &eep_config);
15943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015944
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015945 /*
15946 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15947 * EEPROM configuration that was read.
15948 *
15949 * This is the mapping of EEPROM fields to Adv Library fields.
15950 */
15951 asc_dvc->wdtr_able = eep_config.wdtr_able;
15952 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15953 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15954 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15955 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15956 asc_dvc->ppr_able = 0;
15957 asc_dvc->tagqng_able = eep_config.tagqng_able;
15958 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15959 asc_dvc->max_host_qng = eep_config.max_host_qng;
15960 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15961 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
15962 asc_dvc->start_motor = eep_config.start_motor;
15963 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15964 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15965 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015966
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015967 /*
15968 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15969 * are set, then set an 'sdtr_able' bit for it.
15970 */
15971 asc_dvc->sdtr_able = 0;
15972 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15973 if (tid == 0) {
15974 sdtr_speed = asc_dvc->sdtr_speed1;
15975 } else if (tid == 4) {
15976 sdtr_speed = asc_dvc->sdtr_speed2;
15977 } else if (tid == 8) {
15978 sdtr_speed = asc_dvc->sdtr_speed3;
15979 } else if (tid == 12) {
15980 sdtr_speed = asc_dvc->sdtr_speed4;
15981 }
15982 if (sdtr_speed & ASC_MAX_TID) {
15983 asc_dvc->sdtr_able |= (1 << tid);
15984 }
15985 sdtr_speed >>= 4;
15986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015987
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015988 /*
15989 * Set the host maximum queuing (max. 253, min. 16) and the per device
15990 * maximum queuing (max. 63, min. 4).
15991 */
15992 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15993 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15994 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15995 /* If the value is zero, assume it is uninitialized. */
15996 if (eep_config.max_host_qng == 0) {
15997 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15998 } else {
15999 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16000 }
16001 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016002
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016003 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16004 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16005 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16006 /* If the value is zero, assume it is uninitialized. */
16007 if (eep_config.max_dvc_qng == 0) {
16008 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16009 } else {
16010 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16011 }
16012 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016013
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016014 /*
16015 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16016 * set 'max_dvc_qng' to 'max_host_qng'.
16017 */
16018 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16019 eep_config.max_dvc_qng = eep_config.max_host_qng;
16020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016021
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016022 /*
16023 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
16024 * values based on possibly adjusted EEPROM values.
16025 */
16026 asc_dvc->max_host_qng = eep_config.max_host_qng;
16027 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016028
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016029 /*
16030 * If the EEPROM 'termination' field is set to automatic (0), then set
16031 * the ASC_DVC_CFG 'termination' field to automatic also.
16032 *
16033 * If the termination is specified with a non-zero 'termination'
16034 * value check that a legal value is set and set the ASC_DVC_CFG
16035 * 'termination' field appropriately.
16036 */
16037 if (eep_config.termination_se == 0) {
16038 termination = 0; /* auto termination for SE */
16039 } else {
16040 /* Enable manual control with low off / high off. */
16041 if (eep_config.termination_se == 1) {
16042 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016043
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016044 /* Enable manual control with low off / high on. */
16045 } else if (eep_config.termination_se == 2) {
16046 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016047
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016048 /* Enable manual control with low on / high on. */
16049 } else if (eep_config.termination_se == 3) {
16050 termination = TERM_SE;
16051 } else {
16052 /*
16053 * The EEPROM 'termination_se' field contains a bad value.
16054 * Use automatic termination instead.
16055 */
16056 termination = 0;
16057 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16058 }
16059 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016060
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016061 if (eep_config.termination_lvd == 0) {
16062 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16063 } else {
16064 /* Enable manual control with low off / high off. */
16065 if (eep_config.termination_lvd == 1) {
16066 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016067
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016068 /* Enable manual control with low off / high on. */
16069 } else if (eep_config.termination_lvd == 2) {
16070 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016071
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016072 /* Enable manual control with low on / high on. */
16073 } else if (eep_config.termination_lvd == 3) {
16074 asc_dvc->cfg->termination = termination | TERM_LVD;
16075 } else {
16076 /*
16077 * The EEPROM 'termination_lvd' field contains a bad value.
16078 * Use automatic termination instead.
16079 */
16080 asc_dvc->cfg->termination = termination;
16081 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16082 }
16083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016084
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016085 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016086}
16087
16088/*
16089 * Read EEPROM configuration into the specified buffer.
16090 *
16091 * Return a checksum based on the EEPROM configuration read.
16092 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016093static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016094AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16095{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016096 ushort wval, chksum;
16097 ushort *wbuf;
16098 int eep_addr;
16099 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016100
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016101 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16102 wbuf = (ushort *)cfg_buf;
16103 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016104
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016105 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16106 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16107 wval = AdvReadEEPWord(iop_base, eep_addr);
16108 chksum += wval; /* Checksum is calculated from word values. */
16109 if (*charfields++) {
16110 *wbuf = le16_to_cpu(wval);
16111 } else {
16112 *wbuf = wval;
16113 }
16114 }
16115 /* Read checksum word. */
16116 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16117 wbuf++;
16118 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016119
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016120 /* Read rest of EEPROM not covered by the checksum. */
16121 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16122 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16123 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16124 if (*charfields++) {
16125 *wbuf = le16_to_cpu(*wbuf);
16126 }
16127 }
16128 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016129}
16130
16131/*
16132 * Read EEPROM configuration into the specified buffer.
16133 *
16134 * Return a checksum based on the EEPROM configuration read.
16135 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016136static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016137AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016138{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016139 ushort wval, chksum;
16140 ushort *wbuf;
16141 int eep_addr;
16142 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016143
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016144 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16145 wbuf = (ushort *)cfg_buf;
16146 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016147
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016148 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16149 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16150 wval = AdvReadEEPWord(iop_base, eep_addr);
16151 chksum += wval; /* Checksum is calculated from word values. */
16152 if (*charfields++) {
16153 *wbuf = le16_to_cpu(wval);
16154 } else {
16155 *wbuf = wval;
16156 }
16157 }
16158 /* Read checksum word. */
16159 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16160 wbuf++;
16161 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016162
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016163 /* Read rest of EEPROM not covered by the checksum. */
16164 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16165 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16166 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16167 if (*charfields++) {
16168 *wbuf = le16_to_cpu(*wbuf);
16169 }
16170 }
16171 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016172}
16173
16174/*
16175 * Read EEPROM configuration into the specified buffer.
16176 *
16177 * Return a checksum based on the EEPROM configuration read.
16178 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016179static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016180AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016181{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016182 ushort wval, chksum;
16183 ushort *wbuf;
16184 int eep_addr;
16185 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016186
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016187 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16188 wbuf = (ushort *)cfg_buf;
16189 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016190
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016191 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16192 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16193 wval = AdvReadEEPWord(iop_base, eep_addr);
16194 chksum += wval; /* Checksum is calculated from word values. */
16195 if (*charfields++) {
16196 *wbuf = le16_to_cpu(wval);
16197 } else {
16198 *wbuf = wval;
16199 }
16200 }
16201 /* Read checksum word. */
16202 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16203 wbuf++;
16204 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016205
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016206 /* Read rest of EEPROM not covered by the checksum. */
16207 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16208 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16209 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16210 if (*charfields++) {
16211 *wbuf = le16_to_cpu(*wbuf);
16212 }
16213 }
16214 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016215}
16216
16217/*
16218 * Read the EEPROM from specified location
16219 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016220static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016221{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016222 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16223 ASC_EEP_CMD_READ | eep_word_addr);
16224 AdvWaitEEPCmd(iop_base);
16225 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016226}
16227
16228/*
16229 * Wait for EEPROM command to complete
16230 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016231static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016232{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016233 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016234
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016235 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16236 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16237 ASC_EEP_CMD_DONE) {
16238 break;
16239 }
16240 DvcSleepMilliSecond(1);
16241 }
16242 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16243 0) {
16244 ASC_ASSERT(0);
16245 }
16246 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016247}
16248
16249/*
16250 * Write the EEPROM from 'cfg_buf'.
16251 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016252void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016253AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16254{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016255 ushort *wbuf;
16256 ushort addr, chksum;
16257 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016258
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016259 wbuf = (ushort *)cfg_buf;
16260 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16261 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016263 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16264 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016265
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016266 /*
16267 * Write EEPROM from word 0 to word 20.
16268 */
16269 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16270 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16271 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016272
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016273 if (*charfields++) {
16274 word = cpu_to_le16(*wbuf);
16275 } else {
16276 word = *wbuf;
16277 }
16278 chksum += *wbuf; /* Checksum is calculated from word values. */
16279 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16280 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16281 ASC_EEP_CMD_WRITE | addr);
16282 AdvWaitEEPCmd(iop_base);
16283 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016285
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016286 /*
16287 * Write EEPROM checksum at word 21.
16288 */
16289 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16290 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16291 AdvWaitEEPCmd(iop_base);
16292 wbuf++;
16293 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016294
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016295 /*
16296 * Write EEPROM OEM name at words 22 to 29.
16297 */
16298 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16299 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16300 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016301
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016302 if (*charfields++) {
16303 word = cpu_to_le16(*wbuf);
16304 } else {
16305 word = *wbuf;
16306 }
16307 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16308 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16309 ASC_EEP_CMD_WRITE | addr);
16310 AdvWaitEEPCmd(iop_base);
16311 }
16312 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16313 AdvWaitEEPCmd(iop_base);
16314 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016315}
16316
16317/*
16318 * Write the EEPROM from 'cfg_buf'.
16319 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016320void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016321AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016322{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016323 ushort *wbuf;
16324 ushort *charfields;
16325 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016326
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016327 wbuf = (ushort *)cfg_buf;
16328 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16329 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016330
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016331 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16332 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016333
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016334 /*
16335 * Write EEPROM from word 0 to word 20.
16336 */
16337 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16338 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16339 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016340
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016341 if (*charfields++) {
16342 word = cpu_to_le16(*wbuf);
16343 } else {
16344 word = *wbuf;
16345 }
16346 chksum += *wbuf; /* Checksum is calculated from word values. */
16347 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16348 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16349 ASC_EEP_CMD_WRITE | addr);
16350 AdvWaitEEPCmd(iop_base);
16351 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016353
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016354 /*
16355 * Write EEPROM checksum at word 21.
16356 */
16357 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16358 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16359 AdvWaitEEPCmd(iop_base);
16360 wbuf++;
16361 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016362
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016363 /*
16364 * Write EEPROM OEM name at words 22 to 29.
16365 */
16366 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16367 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16368 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016369
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016370 if (*charfields++) {
16371 word = cpu_to_le16(*wbuf);
16372 } else {
16373 word = *wbuf;
16374 }
16375 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16376 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16377 ASC_EEP_CMD_WRITE | addr);
16378 AdvWaitEEPCmd(iop_base);
16379 }
16380 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16381 AdvWaitEEPCmd(iop_base);
16382 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016383}
16384
16385/*
16386 * Write the EEPROM from 'cfg_buf'.
16387 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016388void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016389AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016390{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016391 ushort *wbuf;
16392 ushort *charfields;
16393 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016394
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016395 wbuf = (ushort *)cfg_buf;
16396 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16397 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016398
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016399 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16400 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016401
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016402 /*
16403 * Write EEPROM from word 0 to word 20.
16404 */
16405 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16406 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16407 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016408
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016409 if (*charfields++) {
16410 word = cpu_to_le16(*wbuf);
16411 } else {
16412 word = *wbuf;
16413 }
16414 chksum += *wbuf; /* Checksum is calculated from word values. */
16415 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16416 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16417 ASC_EEP_CMD_WRITE | addr);
16418 AdvWaitEEPCmd(iop_base);
16419 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016421
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016422 /*
16423 * Write EEPROM checksum at word 21.
16424 */
16425 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16426 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16427 AdvWaitEEPCmd(iop_base);
16428 wbuf++;
16429 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016430
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016431 /*
16432 * Write EEPROM OEM name at words 22 to 29.
16433 */
16434 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16435 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16436 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016437
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016438 if (*charfields++) {
16439 word = cpu_to_le16(*wbuf);
16440 } else {
16441 word = *wbuf;
16442 }
16443 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16444 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16445 ASC_EEP_CMD_WRITE | addr);
16446 AdvWaitEEPCmd(iop_base);
16447 }
16448 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16449 AdvWaitEEPCmd(iop_base);
16450 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016451}
16452
16453/* a_advlib.c */
16454/*
16455 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
16456 *
16457 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
16458 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
16459 * RISC to notify it a new command is ready to be executed.
16460 *
16461 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
16462 * set to SCSI_MAX_RETRY.
16463 *
16464 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
16465 * for DMA addresses or math operations are byte swapped to little-endian
16466 * order.
16467 *
16468 * Return:
16469 * ADV_SUCCESS(1) - The request was successfully queued.
16470 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
16471 * request completes.
16472 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
16473 * host IC error.
16474 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016475static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016476{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016477 ulong last_int_level;
16478 AdvPortAddr iop_base;
16479 ADV_DCNT req_size;
16480 ADV_PADDR req_paddr;
16481 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016482
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016483 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016484
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016485 /*
16486 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
16487 */
16488 if (scsiq->target_id > ADV_MAX_TID) {
16489 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
16490 scsiq->done_status = QD_WITH_ERROR;
16491 return ADV_ERROR;
16492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016494 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016495
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016496 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016497
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016498 /*
16499 * Allocate a carrier ensuring at least one carrier always
16500 * remains on the freelist and initialize fields.
16501 */
16502 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
16503 DvcLeaveCritical(last_int_level);
16504 return ADV_BUSY;
16505 }
16506 asc_dvc->carr_freelist = (ADV_CARR_T *)
16507 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
16508 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016509
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016510 /*
16511 * Set the carrier to be a stopper by setting 'next_vpa'
16512 * to the stopper value. The current stopper will be changed
16513 * below to point to the new stopper.
16514 */
16515 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016516
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016517 /*
16518 * Clear the ADV_SCSI_REQ_Q done flag.
16519 */
16520 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016521
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016522 req_size = sizeof(ADV_SCSI_REQ_Q);
16523 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
16524 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016525
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016526 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
16527 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016528
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016529 /* Wait for assertion before making little-endian */
16530 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016531
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016532 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
16533 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
16534 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016535
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016536 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
16537 /*
16538 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
16539 * order during initialization.
16540 */
16541 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016542
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016543 /*
16544 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
16545 * the microcode. The newly allocated stopper will become the new
16546 * stopper.
16547 */
16548 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016549
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016550 /*
16551 * Set the 'next_vpa' pointer for the old stopper to be the
16552 * physical address of the new stopper. The RISC can only
16553 * follow physical addresses.
16554 */
16555 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016556
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016557 /*
16558 * Set the host adapter stopper pointer to point to the new carrier.
16559 */
16560 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016561
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016562 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16563 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16564 /*
16565 * Tickle the RISC to tell it to read its Command Queue Head pointer.
16566 */
16567 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
16568 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16569 /*
16570 * Clear the tickle value. In the ASC-3550 the RISC flag
16571 * command 'clr_tickle_a' does not work unless the host
16572 * value is cleared.
16573 */
16574 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16575 ADV_TICKLE_NOP);
16576 }
16577 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16578 /*
16579 * Notify the RISC a carrier is ready by writing the physical
16580 * address of the new carrier stopper to the COMMA register.
16581 */
16582 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
16583 le32_to_cpu(new_carrp->carr_pa));
16584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016585
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016586 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016587
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016588 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016589}
16590
16591/*
16592 * Reset SCSI Bus and purge all outstanding requests.
16593 *
16594 * Return Value:
16595 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
16596 * ADV_FALSE(0) - Microcode command failed.
16597 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
16598 * may be hung which requires driver recovery.
16599 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016600static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016601{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016602 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016603
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016604 /*
16605 * Send the SCSI Bus Reset idle start idle command which asserts
16606 * the SCSI Bus Reset signal.
16607 */
16608 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
16609 if (status != ADV_TRUE) {
16610 return status;
16611 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016612
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016613 /*
16614 * Delay for the specified SCSI Bus Reset hold time.
16615 *
16616 * The hold time delay is done on the host because the RISC has no
16617 * microsecond accurate timer.
16618 */
16619 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016620
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016621 /*
16622 * Send the SCSI Bus Reset end idle command which de-asserts
16623 * the SCSI Bus Reset signal and purges any pending requests.
16624 */
16625 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
16626 if (status != ADV_TRUE) {
16627 return status;
16628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016630 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016631
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016632 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016633}
16634
16635/*
16636 * Reset chip and SCSI Bus.
16637 *
16638 * Return Value:
16639 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
16640 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
16641 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016642static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016643{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016644 int status;
16645 ushort wdtr_able, sdtr_able, tagqng_able;
16646 ushort ppr_able = 0;
16647 uchar tid, max_cmd[ADV_MAX_TID + 1];
16648 AdvPortAddr iop_base;
16649 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016650
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016651 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016653 /*
16654 * Save current per TID negotiated values.
16655 */
16656 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16657 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16658 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16659 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16660 }
16661 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16662 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16663 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16664 max_cmd[tid]);
16665 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016666
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016667 /*
16668 * Force the AdvInitAsc3550/38C0800Driver() function to
16669 * perform a SCSI Bus Reset by clearing the BIOS signature word.
16670 * The initialization functions assumes a SCSI Bus Reset is not
16671 * needed if the BIOS signature word is present.
16672 */
16673 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
16674 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016675
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016676 /*
16677 * Stop chip and reset it.
16678 */
16679 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
16680 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
16681 DvcSleepMilliSecond(100);
16682 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
16683 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016684
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016685 /*
16686 * Reset Adv Library error code, if any, and try
16687 * re-initializing the chip.
16688 */
16689 asc_dvc->err_code = 0;
16690 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16691 status = AdvInitAsc38C1600Driver(asc_dvc);
16692 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16693 status = AdvInitAsc38C0800Driver(asc_dvc);
16694 } else {
16695 status = AdvInitAsc3550Driver(asc_dvc);
16696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016697
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016698 /* Translate initialization return value to status value. */
16699 if (status == 0) {
16700 status = ADV_TRUE;
16701 } else {
16702 status = ADV_FALSE;
16703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016704
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016705 /*
16706 * Restore the BIOS signature word.
16707 */
16708 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016709
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016710 /*
16711 * Restore per TID negotiated values.
16712 */
16713 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16714 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16715 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16716 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16717 }
16718 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16719 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16720 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16721 max_cmd[tid]);
16722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016723
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016724 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016725}
16726
16727/*
16728 * Adv Library Interrupt Service Routine
16729 *
16730 * This function is called by a driver's interrupt service routine.
16731 * The function disables and re-enables interrupts.
16732 *
16733 * When a microcode idle command is completed, the ADV_DVC_VAR
16734 * 'idle_cmd_done' field is set to ADV_TRUE.
16735 *
16736 * Note: AdvISR() can be called when interrupts are disabled or even
16737 * when there is no hardware interrupt condition present. It will
16738 * always check for completed idle commands and microcode requests.
16739 * This is an important feature that shouldn't be changed because it
16740 * allows commands to be completed from polling mode loops.
16741 *
16742 * Return:
16743 * ADV_TRUE(1) - interrupt was pending
16744 * ADV_FALSE(0) - no interrupt was pending
16745 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016746static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016747{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016748 AdvPortAddr iop_base;
16749 uchar int_stat;
16750 ushort target_bit;
16751 ADV_CARR_T *free_carrp;
16752 ADV_VADDR irq_next_vpa;
16753 int flags;
16754 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016755
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016756 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016757
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016758 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016759
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016760 /* Reading the register clears the interrupt. */
16761 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016762
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016763 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
16764 ADV_INTR_STATUS_INTRC)) == 0) {
16765 DvcLeaveCritical(flags);
16766 return ADV_FALSE;
16767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016768
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016769 /*
16770 * Notify the driver of an asynchronous microcode condition by
16771 * calling the ADV_DVC_VAR.async_callback function. The function
16772 * is passed the microcode ASC_MC_INTRB_CODE byte value.
16773 */
16774 if (int_stat & ADV_INTR_STATUS_INTRB) {
16775 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016776
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016777 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016778
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016779 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16780 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16781 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
16782 asc_dvc->carr_pending_cnt != 0) {
16783 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16784 ADV_TICKLE_A);
16785 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16786 AdvWriteByteRegister(iop_base,
16787 IOPB_TICKLE,
16788 ADV_TICKLE_NOP);
16789 }
16790 }
16791 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016792
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016793 if (asc_dvc->async_callback != 0) {
16794 (*asc_dvc->async_callback) (asc_dvc, intrb_code);
16795 }
16796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016797
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016798 /*
16799 * Check if the IRQ stopper carrier contains a completed request.
16800 */
16801 while (((irq_next_vpa =
16802 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
16803 /*
16804 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
16805 * The RISC will have set 'areq_vpa' to a virtual address.
16806 *
16807 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
16808 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
16809 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
16810 * in AdvExeScsiQueue().
16811 */
16812 scsiq = (ADV_SCSI_REQ_Q *)
16813 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016814
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016815 /*
16816 * Request finished with good status and the queue was not
16817 * DMAed to host memory by the firmware. Set all status fields
16818 * to indicate good status.
16819 */
16820 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
16821 scsiq->done_status = QD_NO_ERROR;
16822 scsiq->host_status = scsiq->scsi_status = 0;
16823 scsiq->data_cnt = 0L;
16824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016825
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016826 /*
16827 * Advance the stopper pointer to the next carrier
16828 * ignoring the lower four bits. Free the previous
16829 * stopper carrier.
16830 */
16831 free_carrp = asc_dvc->irq_sp;
16832 asc_dvc->irq_sp = (ADV_CARR_T *)
16833 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016834
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016835 free_carrp->next_vpa =
16836 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
16837 asc_dvc->carr_freelist = free_carrp;
16838 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016839
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016840 ASC_ASSERT(scsiq != NULL);
16841 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016842
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016843 /*
16844 * Clear request microcode control flag.
16845 */
16846 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016847
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016848 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016849 * Notify the driver of the completed request by passing
16850 * the ADV_SCSI_REQ_Q pointer to its callback function.
16851 */
16852 scsiq->a_flag |= ADV_SCSIQ_DONE;
16853 (*asc_dvc->isr_callback) (asc_dvc, scsiq);
16854 /*
16855 * Note: After the driver callback function is called, 'scsiq'
16856 * can no longer be referenced.
16857 *
16858 * Fall through and continue processing other completed
16859 * requests...
16860 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016861
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016862 /*
16863 * Disable interrupts again in case the driver inadvertently
16864 * enabled interrupts in its callback function.
16865 *
16866 * The DvcEnterCritical() return value is ignored, because
16867 * the 'flags' saved when AdvISR() was first entered will be
16868 * used to restore the interrupt flag on exit.
16869 */
16870 (void)DvcEnterCritical();
16871 }
16872 DvcLeaveCritical(flags);
16873 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016874}
16875
16876/*
16877 * Send an idle command to the chip and wait for completion.
16878 *
16879 * Command completion is polled for once per microsecond.
16880 *
16881 * The function can be called from anywhere including an interrupt handler.
16882 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
16883 * functions to prevent reentrancy.
16884 *
16885 * Return Values:
16886 * ADV_TRUE - command completed successfully
16887 * ADV_FALSE - command failed
16888 * ADV_ERROR - command timed out
16889 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016890static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070016891AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016892 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016893{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016894 ulong last_int_level;
16895 int result;
16896 ADV_DCNT i, j;
16897 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016898
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016899 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016900
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016901 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016902
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016903 /*
16904 * Clear the idle command status which is set by the microcode
16905 * to a non-zero value to indicate when the command is completed.
16906 * The non-zero result is one of the IDLE_CMD_STATUS_* values
16907 * defined in a_advlib.h.
16908 */
16909 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016910
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016911 /*
16912 * Write the idle command value after the idle command parameter
16913 * has been written to avoid a race condition. If the order is not
16914 * followed, the microcode may process the idle command before the
16915 * parameters have been written to LRAM.
16916 */
16917 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
16918 cpu_to_le32(idle_cmd_parameter));
16919 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016920
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016921 /*
16922 * Tickle the RISC to tell it to process the idle command.
16923 */
16924 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
16925 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16926 /*
16927 * Clear the tickle value. In the ASC-3550 the RISC flag
16928 * command 'clr_tickle_b' does not work unless the host
16929 * value is cleared.
16930 */
16931 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
16932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016933
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016934 /* Wait for up to 100 millisecond for the idle command to timeout. */
16935 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
16936 /* Poll once each microsecond for command completion. */
16937 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
16938 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
16939 result);
16940 if (result != 0) {
16941 DvcLeaveCritical(last_int_level);
16942 return result;
16943 }
16944 DvcDelayMicroSecond(asc_dvc, (ushort)1);
16945 }
16946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016947
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016948 ASC_ASSERT(0); /* The idle command should never timeout. */
16949 DvcLeaveCritical(last_int_level);
16950 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016951}
16952
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060016953static int __devinit
16954advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
16955{
16956 int req_cnt = 0;
16957 adv_req_t *reqp = NULL;
16958 int sg_cnt = 0;
16959 adv_sgblk_t *sgp;
16960 int warn_code, err_code;
16961
16962 /*
16963 * Allocate buffer carrier structures. The total size
16964 * is about 4 KB, so allocate all at once.
16965 */
16966 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
16967 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
16968
16969 if (!boardp->carrp)
16970 goto kmalloc_failed;
16971
16972 /*
16973 * Allocate up to 'max_host_qng' request structures for the Wide
16974 * board. The total size is about 16 KB, so allocate all at once.
16975 * If the allocation fails decrement and try again.
16976 */
16977 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
16978 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
16979
16980 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
16981 "bytes %lu\n", reqp, req_cnt,
16982 (ulong)sizeof(adv_req_t) * req_cnt);
16983
16984 if (reqp)
16985 break;
16986 }
16987
16988 if (!reqp)
16989 goto kmalloc_failed;
16990
16991 boardp->orig_reqp = reqp;
16992
16993 /*
16994 * Allocate up to ADV_TOT_SG_BLOCK request structures for
16995 * the Wide board. Each structure is about 136 bytes.
16996 */
16997 boardp->adv_sgblkp = NULL;
16998 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
16999 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
17000
17001 if (!sgp)
17002 break;
17003
17004 sgp->next_sgblkp = boardp->adv_sgblkp;
17005 boardp->adv_sgblkp = sgp;
17006
17007 }
17008
17009 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
17010 sg_cnt, sizeof(adv_sgblk_t),
17011 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
17012
17013 if (!boardp->adv_sgblkp)
17014 goto kmalloc_failed;
17015
17016 adv_dvc_varp->carrier_buf = boardp->carrp;
17017
17018 /*
17019 * Point 'adv_reqp' to the request structures and
17020 * link them together.
17021 */
17022 req_cnt--;
17023 reqp[req_cnt].next_reqp = NULL;
17024 for (; req_cnt > 0; req_cnt--) {
17025 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
17026 }
17027 boardp->adv_reqp = &reqp[0];
17028
17029 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17030 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
17031 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
17032 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17033 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
17034 "\n");
17035 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
17036 } else {
17037 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
17038 "\n");
17039 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
17040 }
17041 err_code = adv_dvc_varp->err_code;
17042
17043 if (warn_code || err_code) {
17044 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
17045 " error 0x%x\n", boardp->id, warn_code, err_code);
17046 }
17047
17048 goto exit;
17049
17050 kmalloc_failed:
17051 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
17052 "failed\n", boardp->id);
17053 err_code = ADV_ERROR;
17054 exit:
17055 return err_code;
17056}
17057
17058static void advansys_wide_free_mem(asc_board_t *boardp)
17059{
17060 kfree(boardp->carrp);
17061 boardp->carrp = NULL;
17062 kfree(boardp->orig_reqp);
17063 boardp->orig_reqp = boardp->adv_reqp = NULL;
17064 while (boardp->adv_sgblkp) {
17065 adv_sgblk_t *sgp = boardp->adv_sgblkp;
17066 boardp->adv_sgblkp = sgp->next_sgblkp;
17067 kfree(sgp);
17068 }
17069}
17070
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017071static struct Scsi_Host *__devinit
17072advansys_board_found(int iop, struct device *dev, int bus_type)
17073{
17074 struct Scsi_Host *shost;
17075 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
17076 asc_board_t *boardp;
17077 ASC_DVC_VAR *asc_dvc_varp = NULL;
17078 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017079 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017080 int warn_code, err_code;
17081 int ret;
17082
17083 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017084 * Register the adapter, get its configuration, and
17085 * initialize it.
17086 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017087 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
17088 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017089 if (!shost)
17090 return NULL;
17091
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017092 /* Initialize private per board data */
17093 boardp = ASC_BOARDP(shost);
17094 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017095 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017096 spin_lock_init(&boardp->lock);
17097
17098 /*
17099 * Handle both narrow and wide boards.
17100 *
17101 * If a Wide board was detected, set the board structure
17102 * wide board flag. Set-up the board structure based on
17103 * the board type.
17104 */
17105#ifdef CONFIG_PCI
17106 if (bus_type == ASC_IS_PCI &&
17107 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17108 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17109 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17110 boardp->flags |= ASC_IS_WIDE_BOARD;
17111 }
17112#endif /* CONFIG_PCI */
17113
17114 if (ASC_NARROW_BOARD(boardp)) {
17115 ASC_DBG(1, "advansys_board_found: narrow board\n");
17116 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17117 asc_dvc_varp->bus_type = bus_type;
17118 asc_dvc_varp->drv_ptr = boardp;
17119 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17120 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17121 asc_dvc_varp->iop_base = iop;
17122 asc_dvc_varp->isr_callback = asc_isr_callback;
17123 } else {
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017124#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017125 ASC_DBG(1, "advansys_board_found: wide board\n");
17126 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17127 adv_dvc_varp->drv_ptr = boardp;
17128 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
17129 adv_dvc_varp->isr_callback = adv_isr_callback;
17130 adv_dvc_varp->async_callback = adv_async_callback;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017131 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17132 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17133 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17134 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17135 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17136 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17137 } else {
17138 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17139 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17140 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017141
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017142 boardp->asc_n_io_port = pci_resource_len(pdev, 1);
17143 boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
17144 boardp->asc_n_io_port);
17145 if (!boardp->ioremap_addr) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017146 ASC_PRINT3
17147 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017148 boardp->id, pci_resource_start(pdev, 1),
17149 boardp->asc_n_io_port);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017150 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017151 }
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017152 adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr
Matthew Wilcox71f36112007-07-30 08:04:53 -060017153 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017154 adv_dvc_varp->iop_base);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017155
17156 /*
17157 * Even though it isn't used to access wide boards, other
17158 * than for the debug line below, save I/O Port address so
17159 * that it can be reported.
17160 */
17161 boardp->ioport = iop;
17162
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017163 ASC_DBG2(1, "advansys_board_found: iopb_chip_id_1 0x%x, "
17164 "iopw_chip_id_0 0x%x\n", (ushort)inp(iop + 1),
17165 (ushort)inpw(iop));
17166#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017167 }
17168
17169#ifdef CONFIG_PROC_FS
17170 /*
17171 * Allocate buffer for printing information from
17172 * /proc/scsi/advansys/[0...].
17173 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017174 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
17175 if (!boardp->prtbuf) {
17176 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
17177 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
17178 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017179 }
17180#endif /* CONFIG_PROC_FS */
17181
17182 if (ASC_NARROW_BOARD(boardp)) {
17183 asc_dvc_varp->cfg->dev = dev;
17184 /*
17185 * Set the board bus type and PCI IRQ before
17186 * calling AscInitGetConfig().
17187 */
17188 switch (asc_dvc_varp->bus_type) {
17189#ifdef CONFIG_ISA
17190 case ASC_IS_ISA:
17191 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017192 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017193 break;
17194 case ASC_IS_VL:
17195 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017196 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017197 break;
17198 case ASC_IS_EISA:
17199 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017200 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017201 break;
17202#endif /* CONFIG_ISA */
17203#ifdef CONFIG_PCI
17204 case ASC_IS_PCI:
17205 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
17206 asc_dvc_varp->cfg->pci_slot_info =
17207 ASC_PCI_MKID(pdev->bus->number,
17208 PCI_SLOT(pdev->devfn),
17209 PCI_FUNC(pdev->devfn));
17210 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017211 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017212 break;
17213#endif /* CONFIG_PCI */
17214 default:
17215 ASC_PRINT2
17216 ("advansys_board_found: board %d: unknown adapter type: %d\n",
17217 boardp->id, asc_dvc_varp->bus_type);
17218 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017219 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017220 break;
17221 }
17222 } else {
17223 adv_dvc_varp->cfg->dev = dev;
17224 /*
17225 * For Wide boards set PCI information before calling
17226 * AdvInitGetConfig().
17227 */
17228#ifdef CONFIG_PCI
17229 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
17230 adv_dvc_varp->cfg->pci_slot_info =
17231 ASC_PCI_MKID(pdev->bus->number,
17232 PCI_SLOT(pdev->devfn),
17233 PCI_FUNC(pdev->devfn));
17234 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017235 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017236#endif /* CONFIG_PCI */
17237 }
17238
17239 /*
17240 * Read the board configuration.
17241 */
17242 if (ASC_NARROW_BOARD(boardp)) {
17243 /*
17244 * NOTE: AscInitGetConfig() may change the board's
17245 * bus_type value. The bus_type value should no
17246 * longer be used. If the bus_type field must be
17247 * referenced only use the bit-wise AND operator "&".
17248 */
17249 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
17250 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
17251 case 0: /* No error */
17252 break;
17253 case ASC_WARN_IO_PORT_ROTATE:
17254 ASC_PRINT1
17255 ("AscInitGetConfig: board %d: I/O port address modified\n",
17256 boardp->id);
17257 break;
17258 case ASC_WARN_AUTO_CONFIG:
17259 ASC_PRINT1
17260 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
17261 boardp->id);
17262 break;
17263 case ASC_WARN_EEPROM_CHKSUM:
17264 ASC_PRINT1
17265 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
17266 boardp->id);
17267 break;
17268 case ASC_WARN_IRQ_MODIFIED:
17269 ASC_PRINT1
17270 ("AscInitGetConfig: board %d: IRQ modified\n",
17271 boardp->id);
17272 break;
17273 case ASC_WARN_CMD_QNG_CONFLICT:
17274 ASC_PRINT1
17275 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
17276 boardp->id);
17277 break;
17278 default:
17279 ASC_PRINT2
17280 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
17281 boardp->id, ret);
17282 break;
17283 }
17284 if ((err_code = asc_dvc_varp->err_code) != 0) {
17285 ASC_PRINT3
17286 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17287 boardp->id,
17288 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
17289 }
17290 } else {
17291 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
17292 if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
17293 ASC_PRINT2
17294 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
17295 boardp->id, ret);
17296 }
17297 if ((err_code = adv_dvc_varp->err_code) != 0) {
17298 ASC_PRINT2
17299 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
17300 boardp->id, adv_dvc_varp->err_code);
17301 }
17302 }
17303
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017304 if (err_code != 0)
17305 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017306
17307 /*
17308 * Save the EEPROM configuration so that it can be displayed
17309 * from /proc/scsi/advansys/[0...].
17310 */
17311 if (ASC_NARROW_BOARD(boardp)) {
17312
17313 ASCEEP_CONFIG *ep;
17314
17315 /*
17316 * Set the adapter's target id bit in the 'init_tidmask' field.
17317 */
17318 boardp->init_tidmask |=
17319 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
17320
17321 /*
17322 * Save EEPROM settings for the board.
17323 */
17324 ep = &boardp->eep_config.asc_eep;
17325
17326 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
17327 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
17328 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
17329 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
17330 ep->start_motor = asc_dvc_varp->start_motor;
17331 ep->cntl = asc_dvc_varp->dvc_cntl;
17332 ep->no_scam = asc_dvc_varp->no_scam;
17333 ep->max_total_qng = asc_dvc_varp->max_total_qng;
17334 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
17335 /* 'max_tag_qng' is set to the same value for every device. */
17336 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
17337 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
17338 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
17339 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
17340 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
17341 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
17342 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
17343
17344 /*
17345 * Modify board configuration.
17346 */
17347 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
17348 switch (ret = AscInitSetConfig(asc_dvc_varp)) {
17349 case 0: /* No error. */
17350 break;
17351 case ASC_WARN_IO_PORT_ROTATE:
17352 ASC_PRINT1
17353 ("AscInitSetConfig: board %d: I/O port address modified\n",
17354 boardp->id);
17355 break;
17356 case ASC_WARN_AUTO_CONFIG:
17357 ASC_PRINT1
17358 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
17359 boardp->id);
17360 break;
17361 case ASC_WARN_EEPROM_CHKSUM:
17362 ASC_PRINT1
17363 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
17364 boardp->id);
17365 break;
17366 case ASC_WARN_IRQ_MODIFIED:
17367 ASC_PRINT1
17368 ("AscInitSetConfig: board %d: IRQ modified\n",
17369 boardp->id);
17370 break;
17371 case ASC_WARN_CMD_QNG_CONFLICT:
17372 ASC_PRINT1
17373 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
17374 boardp->id);
17375 break;
17376 default:
17377 ASC_PRINT2
17378 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
17379 boardp->id, ret);
17380 break;
17381 }
17382 if (asc_dvc_varp->err_code != 0) {
17383 ASC_PRINT3
17384 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17385 boardp->id,
17386 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017387 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017388 }
17389
17390 /*
17391 * Finish initializing the 'Scsi_Host' structure.
17392 */
17393 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
17394 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
17395 shost->irq = asc_dvc_varp->irq_no;
17396 }
17397 } else {
17398 ADVEEP_3550_CONFIG *ep_3550;
17399 ADVEEP_38C0800_CONFIG *ep_38C0800;
17400 ADVEEP_38C1600_CONFIG *ep_38C1600;
17401
17402 /*
17403 * Save Wide EEP Configuration Information.
17404 */
17405 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17406 ep_3550 = &boardp->eep_config.adv_3550_eep;
17407
17408 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
17409 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
17410 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17411 ep_3550->termination = adv_dvc_varp->cfg->termination;
17412 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
17413 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
17414 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
17415 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
17416 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
17417 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
17418 ep_3550->start_motor = adv_dvc_varp->start_motor;
17419 ep_3550->scsi_reset_delay =
17420 adv_dvc_varp->scsi_reset_wait;
17421 ep_3550->serial_number_word1 =
17422 adv_dvc_varp->cfg->serial1;
17423 ep_3550->serial_number_word2 =
17424 adv_dvc_varp->cfg->serial2;
17425 ep_3550->serial_number_word3 =
17426 adv_dvc_varp->cfg->serial3;
17427 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17428 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
17429
17430 ep_38C0800->adapter_scsi_id =
17431 adv_dvc_varp->chip_scsi_id;
17432 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
17433 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17434 ep_38C0800->termination_lvd =
17435 adv_dvc_varp->cfg->termination;
17436 ep_38C0800->disc_enable =
17437 adv_dvc_varp->cfg->disc_enable;
17438 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
17439 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
17440 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17441 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17442 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17443 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17444 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17445 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17446 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
17447 ep_38C0800->scsi_reset_delay =
17448 adv_dvc_varp->scsi_reset_wait;
17449 ep_38C0800->serial_number_word1 =
17450 adv_dvc_varp->cfg->serial1;
17451 ep_38C0800->serial_number_word2 =
17452 adv_dvc_varp->cfg->serial2;
17453 ep_38C0800->serial_number_word3 =
17454 adv_dvc_varp->cfg->serial3;
17455 } else {
17456 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
17457
17458 ep_38C1600->adapter_scsi_id =
17459 adv_dvc_varp->chip_scsi_id;
17460 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
17461 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17462 ep_38C1600->termination_lvd =
17463 adv_dvc_varp->cfg->termination;
17464 ep_38C1600->disc_enable =
17465 adv_dvc_varp->cfg->disc_enable;
17466 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
17467 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
17468 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17469 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17470 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17471 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17472 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17473 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17474 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
17475 ep_38C1600->scsi_reset_delay =
17476 adv_dvc_varp->scsi_reset_wait;
17477 ep_38C1600->serial_number_word1 =
17478 adv_dvc_varp->cfg->serial1;
17479 ep_38C1600->serial_number_word2 =
17480 adv_dvc_varp->cfg->serial2;
17481 ep_38C1600->serial_number_word3 =
17482 adv_dvc_varp->cfg->serial3;
17483 }
17484
17485 /*
17486 * Set the adapter's target id bit in the 'init_tidmask' field.
17487 */
17488 boardp->init_tidmask |=
17489 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017490 }
17491
17492 /*
17493 * Channels are numbered beginning with 0. For AdvanSys one host
17494 * structure supports one channel. Multi-channel boards have a
17495 * separate host structure for each channel.
17496 */
17497 shost->max_channel = 0;
17498 if (ASC_NARROW_BOARD(boardp)) {
17499 shost->max_id = ASC_MAX_TID + 1;
17500 shost->max_lun = ASC_MAX_LUN + 1;
17501
17502 shost->io_port = asc_dvc_varp->iop_base;
17503 boardp->asc_n_io_port = ASC_IOADR_GAP;
17504 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
17505
17506 /* Set maximum number of queues the adapter can handle. */
17507 shost->can_queue = asc_dvc_varp->max_total_qng;
17508 } else {
17509 shost->max_id = ADV_MAX_TID + 1;
17510 shost->max_lun = ADV_MAX_LUN + 1;
17511
17512 /*
17513 * Save the I/O Port address and length even though
17514 * I/O ports are not used to access Wide boards.
17515 * Instead the Wide boards are accessed with
17516 * PCI Memory Mapped I/O.
17517 */
17518 shost->io_port = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017519
17520 shost->this_id = adv_dvc_varp->chip_scsi_id;
17521
17522 /* Set maximum number of queues the adapter can handle. */
17523 shost->can_queue = adv_dvc_varp->max_host_qng;
17524 }
17525
17526 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017527 * Following v1.3.89, 'cmd_per_lun' is no longer needed
17528 * and should be set to zero.
17529 *
17530 * But because of a bug introduced in v1.3.89 if the driver is
17531 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
17532 * SCSI function 'allocate_device' will panic. To allow the driver
17533 * to work as a module in these kernels set 'cmd_per_lun' to 1.
17534 *
17535 * Note: This is wrong. cmd_per_lun should be set to the depth
17536 * you want on untagged devices always.
17537 #ifdef MODULE
17538 */
17539 shost->cmd_per_lun = 1;
17540/* #else
17541 shost->cmd_per_lun = 0;
17542#endif */
17543
17544 /*
17545 * Set the maximum number of scatter-gather elements the
17546 * adapter can handle.
17547 */
17548 if (ASC_NARROW_BOARD(boardp)) {
17549 /*
17550 * Allow two commands with 'sg_tablesize' scatter-gather
17551 * elements to be executed simultaneously. This value is
17552 * the theoretical hardware limit. It may be decreased
17553 * below.
17554 */
17555 shost->sg_tablesize =
17556 (((asc_dvc_varp->max_total_qng - 2) / 2) *
17557 ASC_SG_LIST_PER_Q) + 1;
17558 } else {
17559 shost->sg_tablesize = ADV_MAX_SG_LIST;
17560 }
17561
17562 /*
17563 * The value of 'sg_tablesize' can not exceed the SCSI
17564 * mid-level driver definition of SG_ALL. SG_ALL also
17565 * must not be exceeded, because it is used to define the
17566 * size of the scatter-gather table in 'struct asc_sg_head'.
17567 */
17568 if (shost->sg_tablesize > SG_ALL) {
17569 shost->sg_tablesize = SG_ALL;
17570 }
17571
17572 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
17573
17574 /* BIOS start address. */
17575 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017576 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
17577 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017578 } else {
17579 /*
17580 * Fill-in BIOS board variables. The Wide BIOS saves
17581 * information in LRAM that is used by the driver.
17582 */
17583 AdvReadWordLram(adv_dvc_varp->iop_base,
17584 BIOS_SIGNATURE, boardp->bios_signature);
17585 AdvReadWordLram(adv_dvc_varp->iop_base,
17586 BIOS_VERSION, boardp->bios_version);
17587 AdvReadWordLram(adv_dvc_varp->iop_base,
17588 BIOS_CODESEG, boardp->bios_codeseg);
17589 AdvReadWordLram(adv_dvc_varp->iop_base,
17590 BIOS_CODELEN, boardp->bios_codelen);
17591
17592 ASC_DBG2(1,
17593 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
17594 boardp->bios_signature, boardp->bios_version);
17595
17596 ASC_DBG2(1,
17597 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
17598 boardp->bios_codeseg, boardp->bios_codelen);
17599
17600 /*
17601 * If the BIOS saved a valid signature, then fill in
17602 * the BIOS code segment base address.
17603 */
17604 if (boardp->bios_signature == 0x55AA) {
17605 /*
17606 * Convert x86 realmode code segment to a linear
17607 * address by shifting left 4.
17608 */
17609 shost->base = ((ulong)boardp->bios_codeseg << 4);
17610 } else {
17611 shost->base = 0;
17612 }
17613 }
17614
17615 /*
17616 * Register Board Resources - I/O Port, DMA, IRQ
17617 */
17618
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017619 /* Register DMA Channel for Narrow boards. */
17620 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
17621#ifdef CONFIG_ISA
17622 if (ASC_NARROW_BOARD(boardp)) {
17623 /* Register DMA channel for ISA bus. */
17624 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
17625 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017626 ret = request_dma(shost->dma_channel, "advansys");
17627 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017628 ASC_PRINT3
17629 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
17630 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017631 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017632 }
17633 AscEnableIsaDma(shost->dma_channel);
17634 }
17635 }
17636#endif /* CONFIG_ISA */
17637
17638 /* Register IRQ Number. */
17639 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017640
17641 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
17642 "advansys", shost);
17643
17644 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017645 if (ret == -EBUSY) {
17646 ASC_PRINT2
17647 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
17648 boardp->id, shost->irq);
17649 } else if (ret == -EINVAL) {
17650 ASC_PRINT2
17651 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
17652 boardp->id, shost->irq);
17653 } else {
17654 ASC_PRINT3
17655 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
17656 boardp->id, shost->irq, ret);
17657 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017658 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017659 }
17660
17661 /*
17662 * Initialize board RISC chip and enable interrupts.
17663 */
17664 if (ASC_NARROW_BOARD(boardp)) {
17665 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
17666 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
17667 err_code = asc_dvc_varp->err_code;
17668
17669 if (warn_code || err_code) {
17670 ASC_PRINT4
17671 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
17672 boardp->id,
17673 asc_dvc_varp->init_state, warn_code, err_code);
17674 }
17675 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017676 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017677 }
17678
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017679 if (err_code != 0)
17680 goto err_free_wide_mem;
17681
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017682 ASC_DBG_PRT_SCSI_HOST(2, shost);
17683
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017684 ret = scsi_add_host(shost, dev);
17685 if (ret)
17686 goto err_free_wide_mem;
17687
17688 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017689 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017690
17691 err_free_wide_mem:
17692 advansys_wide_free_mem(boardp);
17693 free_irq(shost->irq, shost);
17694 err_free_dma:
17695 if (shost->dma_channel != NO_ISA_DMA)
17696 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017697 err_free_proc:
17698 kfree(boardp->prtbuf);
17699 err_unmap:
17700 if (boardp->ioremap_addr)
17701 iounmap(boardp->ioremap_addr);
17702 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017703 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017704 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017705}
17706
17707/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017708 * advansys_release()
17709 *
17710 * Release resources allocated for a single AdvanSys adapter.
17711 */
17712static int advansys_release(struct Scsi_Host *shost)
17713{
17714 asc_board_t *boardp;
17715
17716 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017717 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017718 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017719 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017720 if (shost->dma_channel != NO_ISA_DMA) {
17721 ASC_DBG(1, "advansys_release: free_dma()\n");
17722 free_dma(shost->dma_channel);
17723 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017724 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017725 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017726 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017727 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017728 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017729 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017730 ASC_DBG(1, "advansys_release: end\n");
17731 return 0;
17732}
17733
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017734static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
17735 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
17736 0x0210, 0x0230, 0x0250, 0x0330
17737};
17738
17739static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
17740{
17741 PortAddr iop_base = _asc_def_iop_base[id];
17742 struct Scsi_Host *shost;
17743
17744 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017745 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
17746 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017747 return -ENODEV;
17748 }
17749 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017750 if (!AscFindSignature(iop_base))
17751 goto nodev;
17752 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
17753 goto nodev;
17754
17755 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017756 if (!shost)
17757 goto nodev;
17758
17759 dev_set_drvdata(dev, shost);
17760 return 0;
17761
17762 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060017763 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017764 return -ENODEV;
17765}
17766
17767static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
17768{
Matthew Wilcox71f36112007-07-30 08:04:53 -060017769 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017770 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060017771 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017772 return 0;
17773}
17774
17775static struct isa_driver advansys_isa_driver = {
17776 .probe = advansys_isa_probe,
17777 .remove = __devexit_p(advansys_isa_remove),
17778 .driver = {
17779 .owner = THIS_MODULE,
17780 .name = "advansys",
17781 },
17782};
17783
17784static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
17785{
17786 PortAddr iop_base = _asc_def_iop_base[id];
17787 struct Scsi_Host *shost;
17788
17789 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017790 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
17791 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017792 return -ENODEV;
17793 }
17794 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017795 if (!AscFindSignature(iop_base))
17796 goto nodev;
17797 /*
17798 * I don't think this condition can actually happen, but the old
17799 * driver did it, and the chances of finding a VLB setup in 2007
17800 * to do testing with is slight to none.
17801 */
17802 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
17803 goto nodev;
17804
17805 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017806 if (!shost)
17807 goto nodev;
17808
17809 dev_set_drvdata(dev, shost);
17810 return 0;
17811
17812 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060017813 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017814 return -ENODEV;
17815}
17816
17817static struct isa_driver advansys_vlb_driver = {
17818 .probe = advansys_vlb_probe,
17819 .remove = __devexit_p(advansys_isa_remove),
17820 .driver = {
17821 .owner = THIS_MODULE,
17822 .name = "advansys",
17823 },
17824};
17825
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017826static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
17827 { "ABP7401" },
17828 { "ABP7501" },
17829 { "" }
17830};
17831
17832MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
17833
17834/*
17835 * EISA is a little more tricky than PCI; each EISA device may have two
17836 * channels, and this driver is written to make each channel its own Scsi_Host
17837 */
17838struct eisa_scsi_data {
17839 struct Scsi_Host *host[2];
17840};
17841
17842static int __devinit advansys_eisa_probe(struct device *dev)
17843{
17844 int i, ioport;
17845 int err;
17846 struct eisa_device *edev = to_eisa_device(dev);
17847 struct eisa_scsi_data *data;
17848
17849 err = -ENOMEM;
17850 data = kzalloc(sizeof(*data), GFP_KERNEL);
17851 if (!data)
17852 goto fail;
17853 ioport = edev->base_addr + 0xc30;
17854
17855 err = -ENODEV;
17856 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017857 if (!request_region(ioport, ASC_IOADR_GAP, "advansys")) {
17858 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
17859 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017860 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017861 }
17862 if (!AscFindSignature(ioport)) {
17863 release_region(ioport, ASC_IOADR_GAP);
17864 continue;
17865 }
17866
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017867 /*
17868 * I don't know why we need to do this for EISA chips, but
17869 * not for any others. It looks to be equivalent to
17870 * AscGetChipCfgMsw, but I may have overlooked something,
17871 * so I'm not converting it until I get an EISA board to
17872 * test with.
17873 */
17874 inw(ioport + 4);
17875 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017876 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017877 err = 0;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017878 } else {
17879 release_region(ioport, ASC_IOADR_GAP);
17880 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017881 }
17882
17883 if (err) {
17884 kfree(data);
17885 } else {
17886 dev_set_drvdata(dev, data);
17887 }
17888
17889 fail:
17890 return err;
17891}
17892
17893static __devexit int advansys_eisa_remove(struct device *dev)
17894{
17895 int i;
17896 struct eisa_scsi_data *data = dev_get_drvdata(dev);
17897
17898 for (i = 0; i < 2; i++) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017899 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017900 struct Scsi_Host *shost = data->host[i];
17901 if (!shost)
17902 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017903 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017904 advansys_release(shost);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017905 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017906 }
17907
17908 kfree(data);
17909 return 0;
17910}
17911
17912static struct eisa_driver advansys_eisa_driver = {
17913 .id_table = advansys_eisa_table,
17914 .driver = {
17915 .name = "advansys",
17916 .probe = advansys_eisa_probe,
17917 .remove = __devexit_p(advansys_eisa_remove),
17918 }
17919};
17920
Dave Jones2672ea82006-08-02 17:11:49 -040017921/* PCI Devices supported by this driver */
17922static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017923 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
17924 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17925 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
17926 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17927 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
17928 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17929 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
17930 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17931 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
17932 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17933 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
17934 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17935 {}
Dave Jones2672ea82006-08-02 17:11:49 -040017936};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017937
Dave Jones2672ea82006-08-02 17:11:49 -040017938MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017939
Matthew Wilcox9649af32007-07-26 21:51:47 -060017940static void __devinit advansys_set_latency(struct pci_dev *pdev)
17941{
17942 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
17943 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
17944 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
17945 } else {
17946 u8 latency;
17947 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
17948 if (latency < 0x20)
17949 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
17950 }
17951}
17952
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017953static int __devinit
17954advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
17955{
17956 int err, ioport;
17957 struct Scsi_Host *shost;
17958
17959 err = pci_enable_device(pdev);
17960 if (err)
17961 goto fail;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017962 err = pci_request_regions(pdev, "advansys");
17963 if (err)
17964 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060017965 pci_set_master(pdev);
17966 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017967
17968 if (pci_resource_len(pdev, 0) == 0)
17969 goto nodev;
17970
17971 ioport = pci_resource_start(pdev, 0);
17972 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
17973
17974 if (!shost)
17975 goto nodev;
17976
17977 pci_set_drvdata(pdev, shost);
17978 return 0;
17979
17980 nodev:
17981 err = -ENODEV;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017982 pci_release_regions(pdev);
17983 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017984 pci_disable_device(pdev);
17985 fail:
17986 return err;
17987}
17988
17989static void __devexit advansys_pci_remove(struct pci_dev *pdev)
17990{
17991 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060017992 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017993 pci_disable_device(pdev);
17994}
17995
17996static struct pci_driver advansys_pci_driver = {
17997 .name = "advansys",
17998 .id_table = advansys_pci_tbl,
17999 .probe = advansys_pci_probe,
18000 .remove = __devexit_p(advansys_pci_remove),
18001};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018002
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018003static int __init advansys_init(void)
18004{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018005 int error;
18006
18007 error = isa_register_driver(&advansys_isa_driver,
18008 ASC_IOADR_TABLE_MAX_IX);
18009 if (error)
18010 goto fail;
18011
18012 error = isa_register_driver(&advansys_vlb_driver,
18013 ASC_IOADR_TABLE_MAX_IX);
18014 if (error)
18015 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018016
18017 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018018 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018019 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018020
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018021 error = pci_register_driver(&advansys_pci_driver);
18022 if (error)
18023 goto unregister_eisa;
18024
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018025 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018026
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018027 unregister_eisa:
18028 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018029 unregister_vlb:
18030 isa_unregister_driver(&advansys_vlb_driver);
18031 unregister_isa:
18032 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018033 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018034 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018035}
18036
18037static void __exit advansys_exit(void)
18038{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018039 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018040 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018041 isa_unregister_driver(&advansys_vlb_driver);
18042 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018043}
18044
18045module_init(advansys_init);
18046module_exit(advansys_exit);
18047
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018048MODULE_LICENSE("GPL");