blob: 2f3707613285db6b17754236d60cf9b761d275b6 [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 */
2292#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002294#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2295#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
2297/*
2298 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
2299 * a special 16K Adv Library and Microcode version. After the issue is
2300 * resolved, should restore 32K support.
2301 *
2302 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
2303 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002304#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2305#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
2306#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
2308/*
2309 * Byte I/O register address from base of 'iop_base'.
2310 */
2311#define IOPB_INTR_STATUS_REG 0x00
2312#define IOPB_CHIP_ID_1 0x01
2313#define IOPB_INTR_ENABLES 0x02
2314#define IOPB_CHIP_TYPE_REV 0x03
2315#define IOPB_RES_ADDR_4 0x04
2316#define IOPB_RES_ADDR_5 0x05
2317#define IOPB_RAM_DATA 0x06
2318#define IOPB_RES_ADDR_7 0x07
2319#define IOPB_FLAG_REG 0x08
2320#define IOPB_RES_ADDR_9 0x09
2321#define IOPB_RISC_CSR 0x0A
2322#define IOPB_RES_ADDR_B 0x0B
2323#define IOPB_RES_ADDR_C 0x0C
2324#define IOPB_RES_ADDR_D 0x0D
2325#define IOPB_SOFT_OVER_WR 0x0E
2326#define IOPB_RES_ADDR_F 0x0F
2327#define IOPB_MEM_CFG 0x10
2328#define IOPB_RES_ADDR_11 0x11
2329#define IOPB_GPIO_DATA 0x12
2330#define IOPB_RES_ADDR_13 0x13
2331#define IOPB_FLASH_PAGE 0x14
2332#define IOPB_RES_ADDR_15 0x15
2333#define IOPB_GPIO_CNTL 0x16
2334#define IOPB_RES_ADDR_17 0x17
2335#define IOPB_FLASH_DATA 0x18
2336#define IOPB_RES_ADDR_19 0x19
2337#define IOPB_RES_ADDR_1A 0x1A
2338#define IOPB_RES_ADDR_1B 0x1B
2339#define IOPB_RES_ADDR_1C 0x1C
2340#define IOPB_RES_ADDR_1D 0x1D
2341#define IOPB_RES_ADDR_1E 0x1E
2342#define IOPB_RES_ADDR_1F 0x1F
2343#define IOPB_DMA_CFG0 0x20
2344#define IOPB_DMA_CFG1 0x21
2345#define IOPB_TICKLE 0x22
2346#define IOPB_DMA_REG_WR 0x23
2347#define IOPB_SDMA_STATUS 0x24
2348#define IOPB_SCSI_BYTE_CNT 0x25
2349#define IOPB_HOST_BYTE_CNT 0x26
2350#define IOPB_BYTE_LEFT_TO_XFER 0x27
2351#define IOPB_BYTE_TO_XFER_0 0x28
2352#define IOPB_BYTE_TO_XFER_1 0x29
2353#define IOPB_BYTE_TO_XFER_2 0x2A
2354#define IOPB_BYTE_TO_XFER_3 0x2B
2355#define IOPB_ACC_GRP 0x2C
2356#define IOPB_RES_ADDR_2D 0x2D
2357#define IOPB_DEV_ID 0x2E
2358#define IOPB_RES_ADDR_2F 0x2F
2359#define IOPB_SCSI_DATA 0x30
2360#define IOPB_RES_ADDR_31 0x31
2361#define IOPB_RES_ADDR_32 0x32
2362#define IOPB_SCSI_DATA_HSHK 0x33
2363#define IOPB_SCSI_CTRL 0x34
2364#define IOPB_RES_ADDR_35 0x35
2365#define IOPB_RES_ADDR_36 0x36
2366#define IOPB_RES_ADDR_37 0x37
2367#define IOPB_RAM_BIST 0x38
2368#define IOPB_PLL_TEST 0x39
2369#define IOPB_PCI_INT_CFG 0x3A
2370#define IOPB_RES_ADDR_3B 0x3B
2371#define IOPB_RFIFO_CNT 0x3C
2372#define IOPB_RES_ADDR_3D 0x3D
2373#define IOPB_RES_ADDR_3E 0x3E
2374#define IOPB_RES_ADDR_3F 0x3F
2375
2376/*
2377 * Word I/O register address from base of 'iop_base'.
2378 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002379#define IOPW_CHIP_ID_0 0x00 /* CID0 */
2380#define IOPW_CTRL_REG 0x02 /* CC */
2381#define IOPW_RAM_ADDR 0x04 /* LA */
2382#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002384#define IOPW_RISC_CSR 0x0A /* CSR */
2385#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
2386#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002388#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002390#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002392#define IOPW_EE_CMD 0x1A /* EC */
2393#define IOPW_EE_DATA 0x1C /* ED */
2394#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002396#define IOPW_Q_BASE 0x22 /* QB */
2397#define IOPW_QP 0x24 /* QP */
2398#define IOPW_IX 0x26 /* IX */
2399#define IOPW_SP 0x28 /* SP */
2400#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401#define IOPW_RES_ADDR_2C 0x2C
2402#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002403#define IOPW_SCSI_DATA 0x30 /* SD */
2404#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
2405#define IOPW_SCSI_CTRL 0x34 /* SC */
2406#define IOPW_HSHK_CFG 0x36 /* HCFG */
2407#define IOPW_SXFR_STATUS 0x36 /* SXS */
2408#define IOPW_SXFR_CNTL 0x38 /* SXL */
2409#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002411#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
2413/*
2414 * Doubleword I/O register address from base of 'iop_base'.
2415 */
2416#define IOPDW_RES_ADDR_0 0x00
2417#define IOPDW_RAM_DATA 0x04
2418#define IOPDW_RES_ADDR_8 0x08
2419#define IOPDW_RES_ADDR_C 0x0C
2420#define IOPDW_RES_ADDR_10 0x10
2421#define IOPDW_COMMA 0x14
2422#define IOPDW_COMMB 0x18
2423#define IOPDW_RES_ADDR_1C 0x1C
2424#define IOPDW_SDMA_ADDR0 0x20
2425#define IOPDW_SDMA_ADDR1 0x24
2426#define IOPDW_SDMA_COUNT 0x28
2427#define IOPDW_SDMA_ERROR 0x2C
2428#define IOPDW_RDMA_ADDR0 0x30
2429#define IOPDW_RDMA_ADDR1 0x34
2430#define IOPDW_RDMA_COUNT 0x38
2431#define IOPDW_RDMA_ERROR 0x3C
2432
2433#define ADV_CHIP_ID_BYTE 0x25
2434#define ADV_CHIP_ID_WORD 0x04C1
2435
2436#define ADV_SC_SCSI_BUS_RESET 0x2000
2437
2438#define ADV_INTR_ENABLE_HOST_INTR 0x01
2439#define ADV_INTR_ENABLE_SEL_INTR 0x02
2440#define ADV_INTR_ENABLE_DPR_INTR 0x04
2441#define ADV_INTR_ENABLE_RTA_INTR 0x08
2442#define ADV_INTR_ENABLE_RMA_INTR 0x10
2443#define ADV_INTR_ENABLE_RST_INTR 0x20
2444#define ADV_INTR_ENABLE_DPE_INTR 0x40
2445#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
2446
2447#define ADV_INTR_STATUS_INTRA 0x01
2448#define ADV_INTR_STATUS_INTRB 0x02
2449#define ADV_INTR_STATUS_INTRC 0x04
2450
2451#define ADV_RISC_CSR_STOP (0x0000)
2452#define ADV_RISC_TEST_COND (0x2000)
2453#define ADV_RISC_CSR_RUN (0x4000)
2454#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
2455
2456#define ADV_CTRL_REG_HOST_INTR 0x0100
2457#define ADV_CTRL_REG_SEL_INTR 0x0200
2458#define ADV_CTRL_REG_DPR_INTR 0x0400
2459#define ADV_CTRL_REG_RTA_INTR 0x0800
2460#define ADV_CTRL_REG_RMA_INTR 0x1000
2461#define ADV_CTRL_REG_RES_BIT14 0x2000
2462#define ADV_CTRL_REG_DPE_INTR 0x4000
2463#define ADV_CTRL_REG_POWER_DONE 0x8000
2464#define ADV_CTRL_REG_ANY_INTR 0xFF00
2465
2466#define ADV_CTRL_REG_CMD_RESET 0x00C6
2467#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
2468#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
2469#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
2470#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
2471
2472#define ADV_TICKLE_NOP 0x00
2473#define ADV_TICKLE_A 0x01
2474#define ADV_TICKLE_B 0x02
2475#define ADV_TICKLE_C 0x03
2476
2477#define ADV_SCSI_CTRL_RSTOUT 0x2000
2478
2479#define AdvIsIntPending(port) \
2480 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
2481
2482/*
2483 * SCSI_CFG0 Register bit definitions
2484 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002485#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
2486#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
2487#define EVEN_PARITY 0x1000 /* Select Even Parity */
2488#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
2489#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
2490#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
2491#define SCAM_EN 0x0080 /* Enable SCAM selection */
2492#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
2493#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
2494#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
2495#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496
2497/*
2498 * SCSI_CFG1 Register bit definitions
2499 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002500#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
2501#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
2502#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
2503#define FILTER_SEL 0x0C00 /* Filter Period Selection */
2504#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
2505#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
2506#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
2507#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
2508#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
2509#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
2510#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
2511#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
2512#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
2513#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
2514#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516/*
2517 * Addendum for ASC-38C0800 Chip
2518 *
2519 * The ASC-38C1600 Chip uses the same definitions except that the
2520 * bus mode override bits [12:10] have been moved to byte register
2521 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
2522 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
2523 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
2524 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
2525 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
2526 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002527#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
2528#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
2529#define HVD 0x1000 /* HVD Device Detect */
2530#define LVD 0x0800 /* LVD Device Detect */
2531#define SE 0x0400 /* SE Device Detect */
2532#define TERM_LVD 0x00C0 /* LVD Termination Bits */
2533#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
2534#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
2535#define TERM_SE 0x0030 /* SE Termination Bits */
2536#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
2537#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
2538#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
2539#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
2540#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
2541#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
2542#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
2543#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
2545#define CABLE_ILLEGAL_A 0x7
2546 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
2547
2548#define CABLE_ILLEGAL_B 0xB
2549 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
2550
2551/*
2552 * MEM_CFG Register bit definitions
2553 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002554#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
2555#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
2556#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
2557#define RAM_SZ_2KB 0x00 /* 2 KB */
2558#define RAM_SZ_4KB 0x04 /* 4 KB */
2559#define RAM_SZ_8KB 0x08 /* 8 KB */
2560#define RAM_SZ_16KB 0x0C /* 16 KB */
2561#define RAM_SZ_32KB 0x10 /* 32 KB */
2562#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563
2564/*
2565 * DMA_CFG0 Register bit definitions
2566 *
2567 * This register is only accessible to the host.
2568 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002569#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
2570#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
2571#define FIFO_THRESH_16B 0x00 /* 16 bytes */
2572#define FIFO_THRESH_32B 0x20 /* 32 bytes */
2573#define FIFO_THRESH_48B 0x30 /* 48 bytes */
2574#define FIFO_THRESH_64B 0x40 /* 64 bytes */
2575#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
2576#define FIFO_THRESH_96B 0x60 /* 96 bytes */
2577#define FIFO_THRESH_112B 0x70 /* 112 bytes */
2578#define START_CTL 0x0C /* DMA start conditions */
2579#define START_CTL_TH 0x00 /* Wait threshold level (default) */
2580#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
2581#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
2582#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
2583#define READ_CMD 0x03 /* Memory Read Method */
2584#define READ_CMD_MR 0x00 /* Memory Read */
2585#define READ_CMD_MRL 0x02 /* Memory Read Long */
2586#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587
2588/*
2589 * ASC-38C0800 RAM BIST Register bit definitions
2590 */
2591#define RAM_TEST_MODE 0x80
2592#define PRE_TEST_MODE 0x40
2593#define NORMAL_MODE 0x00
2594#define RAM_TEST_DONE 0x10
2595#define RAM_TEST_STATUS 0x0F
2596#define RAM_TEST_HOST_ERROR 0x08
2597#define RAM_TEST_INTRAM_ERROR 0x04
2598#define RAM_TEST_RISC_ERROR 0x02
2599#define RAM_TEST_SCSI_ERROR 0x01
2600#define RAM_TEST_SUCCESS 0x00
2601#define PRE_TEST_VALUE 0x05
2602#define NORMAL_VALUE 0x00
2603
2604/*
2605 * ASC38C1600 Definitions
2606 *
2607 * IOPB_PCI_INT_CFG Bit Field Definitions
2608 */
2609
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002610#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
2612/*
2613 * Bit 1 can be set to change the interrupt for the Function to operate in
2614 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
2615 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
2616 * mode, otherwise the operating mode is undefined.
2617 */
2618#define TOTEMPOLE 0x02
2619
2620/*
2621 * Bit 0 can be used to change the Int Pin for the Function. The value is
2622 * 0 by default for both Functions with Function 0 using INT A and Function
2623 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
2624 * INT A is used.
2625 *
2626 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
2627 * value specified in the PCI Configuration Space.
2628 */
2629#define INTAB 0x01
2630
2631/* a_advlib.h */
2632
2633/*
2634 * Adv Library Status Definitions
2635 */
2636#define ADV_TRUE 1
2637#define ADV_FALSE 0
2638#define ADV_NOERROR 1
2639#define ADV_SUCCESS 1
2640#define ADV_BUSY 0
2641#define ADV_ERROR (-1)
2642
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643/*
2644 * ADV_DVC_VAR 'warn_code' values
2645 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002646#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
2647#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
2648#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
2649#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
2650#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002652#define ADV_MAX_TID 15 /* max. target identifier */
2653#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
2655/*
2656 * Error code values are set in ADV_DVC_VAR 'err_code'.
2657 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002658#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
2659#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
2660#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
2661#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
2662#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
2663#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
2664#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
2665#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
2666#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
2667#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
2668#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
2669#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
2670#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
2671#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
2673/*
2674 * Fixed locations of microcode operating variables.
2675 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002676#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
2677#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
2678#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
2679#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
2680#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
2681#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
2682#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
2683#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
2684#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
2685#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
2686#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
2687#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
2688#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689#define ASC_MC_CHIP_TYPE 0x009A
2690#define ASC_MC_INTRB_CODE 0x009B
2691#define ASC_MC_WDTR_ABLE 0x009C
2692#define ASC_MC_SDTR_ABLE 0x009E
2693#define ASC_MC_TAGQNG_ABLE 0x00A0
2694#define ASC_MC_DISC_ENABLE 0x00A2
2695#define ASC_MC_IDLE_CMD_STATUS 0x00A4
2696#define ASC_MC_IDLE_CMD 0x00A6
2697#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
2698#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
2699#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
2700#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
2701#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
2702#define ASC_MC_SDTR_DONE 0x00B6
2703#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
2704#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
2705#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002706#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002708#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709#define ASC_MC_ICQ 0x0160
2710#define ASC_MC_IRQ 0x0164
2711#define ASC_MC_PPR_ABLE 0x017A
2712
2713/*
2714 * BIOS LRAM variable absolute offsets.
2715 */
2716#define BIOS_CODESEG 0x54
2717#define BIOS_CODELEN 0x56
2718#define BIOS_SIGNATURE 0x58
2719#define BIOS_VERSION 0x5A
2720
2721/*
2722 * Microcode Control Flags
2723 *
2724 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
2725 * and handled by the microcode.
2726 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002727#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
2728#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
2730/*
2731 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
2732 */
2733#define HSHK_CFG_WIDE_XFR 0x8000
2734#define HSHK_CFG_RATE 0x0F00
2735#define HSHK_CFG_OFFSET 0x001F
2736
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002737#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
2738#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
2739#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
2740#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002742#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2743#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2744#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2745#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2746#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002748#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2749#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2750#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2751#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2752#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753/*
2754 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2755 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2756 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002757#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2758#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
2760/*
2761 * All fields here are accessed by the board microcode and need to be
2762 * little-endian.
2763 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002764typedef struct adv_carr_t {
2765 ADV_VADDR carr_va; /* Carrier Virtual Address */
2766 ADV_PADDR carr_pa; /* Carrier Physical Address */
2767 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2768 /*
2769 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2770 *
2771 * next_vpa [3:1] Reserved Bits
2772 * next_vpa [0] Done Flag set in Response Queue.
2773 */
2774 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775} ADV_CARR_T;
2776
2777/*
2778 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2779 */
2780#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2781
2782#define ASC_RQ_DONE 0x00000001
2783#define ASC_RQ_GOOD 0x00000002
2784#define ASC_CQ_STOPPER 0x00000000
2785
2786#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2787
2788#define ADV_CARRIER_NUM_PAGE_CROSSING \
2789 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2790 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2791
2792#define ADV_CARRIER_BUFSIZE \
2793 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2794
2795/*
2796 * ASC_SCSI_REQ_Q 'a_flag' definitions
2797 *
2798 * The Adv Library should limit use to the lower nibble (4 bits) of
2799 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2800 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002801#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2802#define ADV_SCSIQ_DONE 0x02 /* request done */
2803#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002805#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2806#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2807#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
2809/*
2810 * Adapter temporary configuration structure
2811 *
2812 * This structure can be discarded after initialization. Don't add
2813 * fields here needed after initialization.
2814 *
2815 * Field naming convention:
2816 *
2817 * *_enable indicates the field enables or disables a feature. The
2818 * value of the field is never reset.
2819 */
2820typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002821 ushort disc_enable; /* enable disconnection */
2822 uchar chip_version; /* chip version */
2823 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2824 ushort lib_version; /* Adv Library version number */
2825 ushort control_flag; /* Microcode Control Flag */
2826 ushort mcode_date; /* Microcode date */
2827 ushort mcode_version; /* Microcode version */
2828 ushort pci_slot_info; /* high byte device/function number */
2829 /* bits 7-3 device num., bits 2-0 function num. */
2830 /* low byte bus num. */
2831 ushort serial1; /* EEPROM serial number word 1 */
2832 ushort serial2; /* EEPROM serial number word 2 */
2833 ushort serial3; /* EEPROM serial number word 3 */
2834 struct device *dev; /* pointer to the pci dev structure for this board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835} ADV_DVC_CFG;
2836
2837struct adv_dvc_var;
2838struct adv_scsi_req_q;
2839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002840typedef void (*ADV_ISR_CALLBACK)
2841 (struct adv_dvc_var *, struct adv_scsi_req_q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002843typedef void (*ADV_ASYNC_CALLBACK)
2844 (struct adv_dvc_var *, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
2846/*
2847 * Adapter operation variable structure.
2848 *
2849 * One structure is required per host adapter.
2850 *
2851 * Field naming convention:
2852 *
2853 * *_able indicates both whether a feature should be enabled or disabled
2854 * and whether a device isi capable of the feature. At initialization
2855 * this field may be set, but later if a device is found to be incapable
2856 * of the feature, the field is cleared.
2857 */
2858typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002859 AdvPortAddr iop_base; /* I/O port address */
2860 ushort err_code; /* fatal error code */
2861 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
2862 ADV_ISR_CALLBACK isr_callback;
2863 ADV_ASYNC_CALLBACK async_callback;
2864 ushort wdtr_able; /* try WDTR for a device */
2865 ushort sdtr_able; /* try SDTR for a device */
2866 ushort ultra_able; /* try SDTR Ultra speed for a device */
2867 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2868 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2869 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2870 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2871 ushort tagqng_able; /* try tagged queuing with a device */
2872 ushort ppr_able; /* PPR message capable per TID bitmask. */
2873 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2874 ushort start_motor; /* start motor command allowed */
2875 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2876 uchar chip_no; /* should be assigned by caller */
2877 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2878 uchar irq_no; /* IRQ number */
2879 ushort no_scam; /* scam_tolerant of EEPROM */
2880 struct asc_board *drv_ptr; /* driver pointer to private structure */
2881 uchar chip_scsi_id; /* chip SCSI target ID */
2882 uchar chip_type;
2883 uchar bist_err_code;
2884 ADV_CARR_T *carrier_buf;
2885 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2886 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2887 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2888 ushort carr_pending_cnt; /* Count of pending carriers. */
2889 /*
2890 * Note: The following fields will not be used after initialization. The
2891 * driver may discard the buffer after initialization is done.
2892 */
2893 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894} ADV_DVC_VAR;
2895
2896#define NO_OF_SG_PER_BLOCK 15
2897
2898typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002899 uchar reserved1;
2900 uchar reserved2;
2901 uchar reserved3;
2902 uchar sg_cnt; /* Valid entries in block. */
2903 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
2904 struct {
2905 ADV_PADDR sg_addr; /* SG element address. */
2906 ADV_DCNT sg_count; /* SG element count. */
2907 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908} ADV_SG_BLOCK;
2909
2910/*
2911 * ADV_SCSI_REQ_Q - microcode request structure
2912 *
2913 * All fields in this structure up to byte 60 are used by the microcode.
2914 * The microcode makes assumptions about the size and ordering of fields
2915 * in this structure. Do not change the structure definition here without
2916 * coordinating the change with the microcode.
2917 *
2918 * All fields accessed by microcode must be maintained in little_endian
2919 * order.
2920 */
2921typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002922 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
2923 uchar target_cmd;
2924 uchar target_id; /* Device target identifier. */
2925 uchar target_lun; /* Device target logical unit number. */
2926 ADV_PADDR data_addr; /* Data buffer physical address. */
2927 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
2928 ADV_PADDR sense_addr;
2929 ADV_PADDR carr_pa;
2930 uchar mflag;
2931 uchar sense_len;
2932 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
2933 uchar scsi_cntl;
2934 uchar done_status; /* Completion status. */
2935 uchar scsi_status; /* SCSI status byte. */
2936 uchar host_status; /* Ucode host status. */
2937 uchar sg_working_ix;
2938 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
2939 ADV_PADDR sg_real_addr; /* SG list physical address. */
2940 ADV_PADDR scsiq_rptr;
2941 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
2942 ADV_VADDR scsiq_ptr;
2943 ADV_VADDR carr_va;
2944 /*
2945 * End of microcode structure - 60 bytes. The rest of the structure
2946 * is used by the Adv Library and ignored by the microcode.
2947 */
2948 ADV_VADDR srb_ptr;
2949 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
2950 char *vdata_addr; /* Data buffer virtual address. */
2951 uchar a_flag;
2952 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953} ADV_SCSI_REQ_Q;
2954
2955/*
2956 * Microcode idle loop commands
2957 */
2958#define IDLE_CMD_COMPLETED 0
2959#define IDLE_CMD_STOP_CHIP 0x0001
2960#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
2961#define IDLE_CMD_SEND_INT 0x0004
2962#define IDLE_CMD_ABORT 0x0008
2963#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002964#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
2965#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966#define IDLE_CMD_SCSIREQ 0x0080
2967
2968#define IDLE_CMD_STATUS_SUCCESS 0x0001
2969#define IDLE_CMD_STATUS_FAILURE 0x0002
2970
2971/*
2972 * AdvSendIdleCmd() flag definitions.
2973 */
2974#define ADV_NOWAIT 0x01
2975
2976/*
2977 * Wait loop time out values.
2978 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002979#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
2980#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
2981#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
2982#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
2983#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002985#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
2986#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
2987#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
2988#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002990#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991
2992/*
2993 * Device drivers must define the following functions.
2994 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002995static inline ulong DvcEnterCritical(void);
2996static inline void DvcLeaveCritical(ulong);
2997static void DvcSleepMilliSecond(ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002998static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
2999 uchar *, ASC_SDCNT *, int);
3000static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001
3002/*
3003 * Adv Library functions available to drivers.
3004 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003005static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3006static int AdvISR(ADV_DVC_VAR *);
3007static int AdvInitGetConfig(ADV_DVC_VAR *);
3008static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
3009static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
3010static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
3011static int AdvResetChipAndSB(ADV_DVC_VAR *);
3012static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013
3014/*
3015 * Internal Adv Library functions.
3016 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003017static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003018static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
3019static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
3020static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
3021static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3022static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3023static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3024static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3025static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3026static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3027static void AdvWaitEEPCmd(AdvPortAddr);
3028static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030/* Read byte from a register. */
3031#define AdvReadByteRegister(iop_base, reg_off) \
3032 (ADV_MEM_READB((iop_base) + (reg_off)))
3033
3034/* Write byte to a register. */
3035#define AdvWriteByteRegister(iop_base, reg_off, byte) \
3036 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
3037
3038/* Read word (2 bytes) from a register. */
3039#define AdvReadWordRegister(iop_base, reg_off) \
3040 (ADV_MEM_READW((iop_base) + (reg_off)))
3041
3042/* Write word (2 bytes) to a register. */
3043#define AdvWriteWordRegister(iop_base, reg_off, word) \
3044 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
3045
3046/* Write dword (4 bytes) to a register. */
3047#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
3048 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
3049
3050/* Read byte from LRAM. */
3051#define AdvReadByteLram(iop_base, addr, byte) \
3052do { \
3053 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3054 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
3055} while (0)
3056
3057/* Write byte to LRAM. */
3058#define AdvWriteByteLram(iop_base, addr, byte) \
3059 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3060 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
3061
3062/* Read word (2 bytes) from LRAM. */
3063#define AdvReadWordLram(iop_base, addr, word) \
3064do { \
3065 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3066 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
3067} while (0)
3068
3069/* Write word (2 bytes) to LRAM. */
3070#define AdvWriteWordLram(iop_base, addr, word) \
3071 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3072 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3073
3074/* Write little-endian double word (4 bytes) to LRAM */
3075/* Because of unspecified C language ordering don't use auto-increment. */
3076#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
3077 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3078 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3079 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
3080 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
3081 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3082 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
3083
3084/* Read word (2 bytes) from LRAM assuming that the address is already set. */
3085#define AdvReadWordAutoIncLram(iop_base) \
3086 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
3087
3088/* Write word (2 bytes) to LRAM assuming that the address is already set. */
3089#define AdvWriteWordAutoIncLram(iop_base, word) \
3090 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3091
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092/*
3093 * Define macro to check for Condor signature.
3094 *
3095 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
3096 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
3097 */
3098#define AdvFindSignature(iop_base) \
3099 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
3100 ADV_CHIP_ID_BYTE) && \
3101 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
3102 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
3103
3104/*
3105 * Define macro to Return the version number of the chip at 'iop_base'.
3106 *
3107 * The second parameter 'bus_type' is currently unused.
3108 */
3109#define AdvGetChipVersion(iop_base, bus_type) \
3110 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
3111
3112/*
3113 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
3114 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
3115 *
3116 * If the request has not yet been sent to the device it will simply be
3117 * aborted from RISC memory. If the request is disconnected it will be
3118 * aborted on reselection by sending an Abort Message to the target ID.
3119 *
3120 * Return value:
3121 * ADV_TRUE(1) - Queue was successfully aborted.
3122 * ADV_FALSE(0) - Queue was not found on the active queue list.
3123 */
3124#define AdvAbortQueue(asc_dvc, scsiq) \
3125 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
3126 (ADV_DCNT) (scsiq))
3127
3128/*
3129 * Send a Bus Device Reset Message to the specified target ID.
3130 *
3131 * All outstanding commands will be purged if sending the
3132 * Bus Device Reset Message is successful.
3133 *
3134 * Return Value:
3135 * ADV_TRUE(1) - All requests on the target are purged.
3136 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
3137 * are not purged.
3138 */
3139#define AdvResetDevice(asc_dvc, target_id) \
3140 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
3141 (ADV_DCNT) (target_id))
3142
3143/*
3144 * SCSI Wide Type definition.
3145 */
3146#define ADV_SCSI_BIT_ID_TYPE ushort
3147
3148/*
3149 * AdvInitScsiTarget() 'cntl_flag' options.
3150 */
3151#define ADV_SCAN_LUN 0x01
3152#define ADV_CAPINFO_NOLUN 0x02
3153
3154/*
3155 * Convert target id to target id bit mask.
3156 */
3157#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
3158
3159/*
3160 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
3161 */
3162
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003163#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164#define QD_NO_ERROR 0x01
3165#define QD_ABORTED_BY_HOST 0x02
3166#define QD_WITH_ERROR 0x04
3167
3168#define QHSTA_NO_ERROR 0x00
3169#define QHSTA_M_SEL_TIMEOUT 0x11
3170#define QHSTA_M_DATA_OVER_RUN 0x12
3171#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
3172#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003173#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
3174#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
3175#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
3176#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
3177#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
3178#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
3179#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003181#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
3182#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
3183#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
3184#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
3185#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
3186#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
3187#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
3188#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189#define QHSTA_M_WTM_TIMEOUT 0x41
3190#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
3191#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
3192#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003193#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
3194#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
3195#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196
3197/*
3198 * Default EEPROM Configuration structure defined in a_init.c.
3199 */
3200static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
3201static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
3202static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
3203
3204/*
3205 * DvcGetPhyAddr() flag arguments
3206 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003207#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
3208#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
3209#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
3210#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
3211#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
3212#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
3214/* Return the address that is aligned at the next doubleword >= to 'addr'. */
3215#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
3216#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
3217#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
3218
3219/*
3220 * Total contiguous memory needed for driver SG blocks.
3221 *
3222 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
3223 * number of scatter-gather elements the driver supports in a
3224 * single request.
3225 */
3226
3227#define ADV_SG_LIST_MAX_BYTE_SIZE \
3228 (sizeof(ADV_SG_BLOCK) * \
3229 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
3230
3231/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 * --- Driver Constants and Macros
3233 */
3234
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235/* Reference Scsi_Host hostdata */
3236#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
3237
3238/* asc_board_t flags */
3239#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003240#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241#define ASC_SELECT_QUEUE_DEPTHS 0x08
3242
3243#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
3244#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
3245
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003246#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003248#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249
3250#ifdef CONFIG_PROC_FS
3251/* /proc/scsi/advansys/[0...] related definitions */
3252#define ASC_PRTBUF_SIZE 2048
3253#define ASC_PRTLINE_SIZE 160
3254
3255#define ASC_PRT_NEXT() \
3256 if (cp) { \
3257 totlen += len; \
3258 leftlen -= len; \
3259 if (leftlen == 0) { \
3260 return totlen; \
3261 } \
3262 cp += len; \
3263 }
3264#endif /* CONFIG_PROC_FS */
3265
3266/* Asc Library return codes */
3267#define ASC_TRUE 1
3268#define ASC_FALSE 0
3269#define ASC_NOERROR 1
3270#define ASC_BUSY 0
3271#define ASC_ERROR (-1)
3272
3273/* struct scsi_cmnd function return codes */
3274#define STATUS_BYTE(byte) (byte)
3275#define MSG_BYTE(byte) ((byte) << 8)
3276#define HOST_BYTE(byte) ((byte) << 16)
3277#define DRIVER_BYTE(byte) ((byte) << 24)
3278
3279/*
3280 * The following definitions and macros are OS independent interfaces to
3281 * the queue functions:
3282 * REQ - SCSI request structure
3283 * REQP - pointer to SCSI request structure
3284 * REQPTID(reqp) - reqp's target id
3285 * REQPNEXT(reqp) - reqp's next pointer
3286 * REQPNEXTP(reqp) - pointer to reqp's next pointer
3287 * REQPTIME(reqp) - reqp's time stamp value
3288 * REQTIMESTAMP() - system time stamp value
3289 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003290typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
3292#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
3293#define REQPTID(reqp) ((reqp)->device->id)
3294#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
3295#define REQTIMESTAMP() (jiffies)
3296
3297#define REQTIMESTAT(function, ascq, reqp, tid) \
3298{ \
3299 /*
3300 * If the request time stamp is less than the system time stamp, then \
3301 * maybe the system time stamp wrapped. Set the request time to zero.\
3302 */ \
3303 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
3304 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
3305 } else { \
3306 /* Indicate an error occurred with the assertion. */ \
3307 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
3308 REQPTIME(reqp) = 0; \
3309 } \
3310 /* Handle first minimum time case without external initialization. */ \
3311 if (((ascq)->q_tot_cnt[tid] == 1) || \
3312 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
3313 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
3314 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
3315 (function), (tid), (ascq)->q_min_tim[tid]); \
3316 } \
3317 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
3318 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
3319 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
3320 (function), tid, (ascq)->q_max_tim[tid]); \
3321 } \
3322 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
3323 /* Reset the time stamp field. */ \
3324 REQPTIME(reqp) = 0; \
3325}
3326
3327/* asc_enqueue() flags */
3328#define ASC_FRONT 1
3329#define ASC_BACK 2
3330
3331/* asc_dequeue_list() argument */
3332#define ASC_TID_ALL (-1)
3333
3334/* Return non-zero, if the queue is empty. */
3335#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
3336
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003338#define ASC_STATS(shost, counter)
3339#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003341#define ASC_STATS(shost, counter) \
3342 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003344#define ASC_STATS_ADD(shost, counter, count) \
3345 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346#endif /* ADVANSYS_STATS */
3347
3348#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
3349
3350/* If the result wraps when calculating tenths, return 0. */
3351#define ASC_TENTHS(num, den) \
3352 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
3353 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
3354
3355/*
3356 * Display a message to the console.
3357 */
3358#define ASC_PRINT(s) \
3359 { \
3360 printk("advansys: "); \
3361 printk(s); \
3362 }
3363
3364#define ASC_PRINT1(s, a1) \
3365 { \
3366 printk("advansys: "); \
3367 printk((s), (a1)); \
3368 }
3369
3370#define ASC_PRINT2(s, a1, a2) \
3371 { \
3372 printk("advansys: "); \
3373 printk((s), (a1), (a2)); \
3374 }
3375
3376#define ASC_PRINT3(s, a1, a2, a3) \
3377 { \
3378 printk("advansys: "); \
3379 printk((s), (a1), (a2), (a3)); \
3380 }
3381
3382#define ASC_PRINT4(s, a1, a2, a3, a4) \
3383 { \
3384 printk("advansys: "); \
3385 printk((s), (a1), (a2), (a3), (a4)); \
3386 }
3387
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388#ifndef ADVANSYS_DEBUG
3389
3390#define ASC_DBG(lvl, s)
3391#define ASC_DBG1(lvl, s, a1)
3392#define ASC_DBG2(lvl, s, a1, a2)
3393#define ASC_DBG3(lvl, s, a1, a2, a3)
3394#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
3395#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
3396#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
3397#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
3398#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3399#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
3400#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3401#define ASC_DBG_PRT_HEX(lvl, name, start, length)
3402#define ASC_DBG_PRT_CDB(lvl, cdb, len)
3403#define ASC_DBG_PRT_SENSE(lvl, sense, len)
3404#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
3405
3406#else /* ADVANSYS_DEBUG */
3407
3408/*
3409 * Debugging Message Levels:
3410 * 0: Errors Only
3411 * 1: High-Level Tracing
3412 * 2-N: Verbose Tracing
3413 */
3414
3415#define ASC_DBG(lvl, s) \
3416 { \
3417 if (asc_dbglvl >= (lvl)) { \
3418 printk(s); \
3419 } \
3420 }
3421
3422#define ASC_DBG1(lvl, s, a1) \
3423 { \
3424 if (asc_dbglvl >= (lvl)) { \
3425 printk((s), (a1)); \
3426 } \
3427 }
3428
3429#define ASC_DBG2(lvl, s, a1, a2) \
3430 { \
3431 if (asc_dbglvl >= (lvl)) { \
3432 printk((s), (a1), (a2)); \
3433 } \
3434 }
3435
3436#define ASC_DBG3(lvl, s, a1, a2, a3) \
3437 { \
3438 if (asc_dbglvl >= (lvl)) { \
3439 printk((s), (a1), (a2), (a3)); \
3440 } \
3441 }
3442
3443#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
3444 { \
3445 if (asc_dbglvl >= (lvl)) { \
3446 printk((s), (a1), (a2), (a3), (a4)); \
3447 } \
3448 }
3449
3450#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
3451 { \
3452 if (asc_dbglvl >= (lvl)) { \
3453 asc_prt_scsi_host(s); \
3454 } \
3455 }
3456
3457#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
3458 { \
3459 if (asc_dbglvl >= (lvl)) { \
3460 asc_prt_scsi_cmnd(s); \
3461 } \
3462 }
3463
3464#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
3465 { \
3466 if (asc_dbglvl >= (lvl)) { \
3467 asc_prt_asc_scsi_q(scsiqp); \
3468 } \
3469 }
3470
3471#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
3472 { \
3473 if (asc_dbglvl >= (lvl)) { \
3474 asc_prt_asc_qdone_info(qdone); \
3475 } \
3476 }
3477
3478#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
3479 { \
3480 if (asc_dbglvl >= (lvl)) { \
3481 asc_prt_adv_scsi_req_q(scsiqp); \
3482 } \
3483 }
3484
3485#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
3486 { \
3487 if (asc_dbglvl >= (lvl)) { \
3488 asc_prt_hex((name), (start), (length)); \
3489 } \
3490 }
3491
3492#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
3493 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
3494
3495#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
3496 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
3497
3498#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
3499 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
3500#endif /* ADVANSYS_DEBUG */
3501
3502#ifndef ADVANSYS_ASSERT
3503#define ASC_ASSERT(a)
3504#else /* ADVANSYS_ASSERT */
3505
3506#define ASC_ASSERT(a) \
3507 { \
3508 if (!(a)) { \
3509 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
3510 __FILE__, __LINE__); \
3511 } \
3512 }
3513
3514#endif /* ADVANSYS_ASSERT */
3515
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516/*
3517 * --- Driver Structures
3518 */
3519
3520#ifdef ADVANSYS_STATS
3521
3522/* Per board statistics structure */
3523struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003524 /* Driver Entrypoint Statistics */
3525 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
3526 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
3527 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
3528 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
3529 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
3530 ADV_DCNT done; /* # calls to request's scsi_done function */
3531 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
3532 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
3533 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
3534 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
3535 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
3536 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
3537 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
3538 ADV_DCNT exe_unknown; /* # unknown returns. */
3539 /* Data Transfer Statistics */
3540 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
3541 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
3542 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
3543 ADV_DCNT sg_elem; /* # scatter-gather elements */
3544 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545};
3546#endif /* ADVANSYS_STATS */
3547
3548/*
3549 * Request queuing structure
3550 */
3551typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003552 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
3553 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
3554 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003556 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
3557 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
3558 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
3559 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
3560 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
3561 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
3562#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563} asc_queue_t;
3564
3565/*
3566 * Adv Library Request Structures
3567 *
3568 * The following two structures are used to process Wide Board requests.
3569 *
3570 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
3571 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
3572 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
3573 * Mid-Level SCSI request structure.
3574 *
3575 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
3576 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
3577 * up to 255 scatter-gather elements may be used per request or
3578 * ADV_SCSI_REQ_Q.
3579 *
3580 * Both structures must be 32 byte aligned.
3581 */
3582typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003583 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
3584 uchar align[32]; /* Sgblock structure padding. */
3585 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586} adv_sgblk_t;
3587
3588typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003589 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
3590 uchar align[32]; /* Request structure padding. */
3591 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
3592 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
3593 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594} adv_req_t;
3595
3596/*
3597 * Structure allocated for each board.
3598 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003599 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 * of the 'Scsi_Host' structure starting at the 'hostdata'
3601 * field. It is guaranteed to be allocated from DMA-able memory.
3602 */
3603typedef struct asc_board {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003604 int id; /* Board Id */
3605 uint flags; /* Board flags */
3606 union {
3607 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
3608 ADV_DVC_VAR adv_dvc_var; /* Wide board */
3609 } dvc_var;
3610 union {
3611 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
3612 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
3613 } dvc_cfg;
3614 ushort asc_n_io_port; /* Number I/O ports. */
3615 asc_queue_t active; /* Active command queue */
3616 asc_queue_t waiting; /* Waiting command queue */
3617 asc_queue_t done; /* Done command queue */
3618 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
3619 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
3620 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
3621 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
3622 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
3623 union {
3624 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
3625 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
3626 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
3627 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
3628 } eep_config;
3629 ulong last_reset; /* Saved last reset time */
3630 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003631 /* /proc/scsi/advansys/[0...] */
3632 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003634 struct asc_stats asc_stats; /* Board statistics */
3635#endif /* ADVANSYS_STATS */
3636 /*
3637 * The following fields are used only for Narrow Boards.
3638 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003639 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3640 /*
3641 * The following fields are used only for Wide Boards.
3642 */
3643 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3644 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06003645 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003646 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3647 adv_req_t *adv_reqp; /* Request structures. */
3648 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3649 ushort bios_signature; /* BIOS Signature. */
3650 ushort bios_version; /* BIOS Version. */
3651 ushort bios_codeseg; /* BIOS Code Segment. */
3652 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653} asc_board_t;
3654
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06003656static int asc_board_count;
3657
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003659static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660
3661/*
3662 * Global structures required to issue a command.
3663 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003664static ASC_SCSI_Q asc_scsi_q = { {0} };
3665static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003668static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669#endif /* ADVANSYS_DEBUG */
3670
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671/*
3672 * --- Driver Function Prototypes
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 */
3674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003675static int advansys_slave_configure(struct scsi_device *);
3676static void asc_scsi_done_list(struct scsi_cmnd *);
3677static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3678static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3679static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3680static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
3681static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
3682static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3683static void adv_async_callback(ADV_DVC_VAR *, uchar);
3684static void asc_enqueue(asc_queue_t *, REQP, int);
3685static REQP asc_dequeue(asc_queue_t *, int);
3686static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3687static int asc_rmqueue(asc_queue_t *, REQP);
3688static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003690static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3691static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3692static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3693static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3694static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3695static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3696static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3697static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3698static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3699static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700#endif /* CONFIG_PROC_FS */
3701
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702/* Statistics function prototypes. */
3703#ifdef ADVANSYS_STATS
3704#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003705static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3706static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707#endif /* CONFIG_PROC_FS */
3708#endif /* ADVANSYS_STATS */
3709
3710/* Debug function prototypes. */
3711#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003712static void asc_prt_scsi_host(struct Scsi_Host *);
3713static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
3714static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
3715static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
3716static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
3717static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
3718static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
3719static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
3720static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
3721static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
3722static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723#endif /* ADVANSYS_DEBUG */
3724
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725#ifdef CONFIG_PROC_FS
3726/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06003727 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 *
3729 * *buffer: I/O buffer
3730 * **start: if inout == FALSE pointer into buffer where user read should start
3731 * offset: current offset into a /proc/scsi/advansys/[0...] file
3732 * length: length of buffer
3733 * hostno: Scsi_Host host_no
3734 * inout: TRUE - user is writing; FALSE - user is reading
3735 *
3736 * Return the number of bytes read from or written to a
3737 * /proc/scsi/advansys/[0...] file.
3738 *
3739 * Note: This function uses the per board buffer 'prtbuf' which is
3740 * allocated when the board is initialized in advansys_detect(). The
3741 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
3742 * used to write to the buffer. The way asc_proc_copy() is written
3743 * if 'prtbuf' is too small it will not be overwritten. Instead the
3744 * user just won't get all the available statistics.
3745 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003746static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003748 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003750 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003751 char *cp;
3752 int cplen;
3753 int cnt;
3754 int totcnt;
3755 int leftlen;
3756 char *curbuf;
3757 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003759 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760#endif /* ADVANSYS_STATS */
3761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003762 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003764 /*
3765 * User write not supported.
3766 */
3767 if (inout == TRUE) {
3768 return (-ENOSYS);
3769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003771 /*
3772 * User read of /proc/scsi/advansys/[0...] file.
3773 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774
Matthew Wilcox2a437952007-07-26 11:00:51 -04003775 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003777 /* Copy read data starting at the beginning of the buffer. */
3778 *start = buffer;
3779 curbuf = buffer;
3780 advoffset = 0;
3781 totcnt = 0;
3782 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003784 /*
3785 * Get board configuration information.
3786 *
3787 * advansys_info() returns the board string from its own static buffer.
3788 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04003789 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003790 strcat(cp, "\n");
3791 cplen = strlen(cp);
3792 /* Copy board information. */
3793 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3794 totcnt += cnt;
3795 leftlen -= cnt;
3796 if (leftlen == 0) {
3797 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3798 return totcnt;
3799 }
3800 advoffset += cplen;
3801 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003803 /*
3804 * Display Wide Board BIOS Information.
3805 */
3806 if (ASC_WIDE_BOARD(boardp)) {
3807 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003808 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003809 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003810 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003811 cplen);
3812 totcnt += cnt;
3813 leftlen -= cnt;
3814 if (leftlen == 0) {
3815 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3816 return totcnt;
3817 }
3818 advoffset += cplen;
3819 curbuf += cnt;
3820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003822 /*
3823 * Display driver information for each device attached to the board.
3824 */
3825 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003826 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003827 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3828 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3829 totcnt += cnt;
3830 leftlen -= cnt;
3831 if (leftlen == 0) {
3832 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3833 return totcnt;
3834 }
3835 advoffset += cplen;
3836 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003838 /*
3839 * Display EEPROM configuration for the board.
3840 */
3841 cp = boardp->prtbuf;
3842 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003843 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003844 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003845 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003846 }
3847 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3848 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3849 totcnt += cnt;
3850 leftlen -= cnt;
3851 if (leftlen == 0) {
3852 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3853 return totcnt;
3854 }
3855 advoffset += cplen;
3856 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003858 /*
3859 * Display driver configuration and information for the board.
3860 */
3861 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003862 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003863 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3864 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3865 totcnt += cnt;
3866 leftlen -= cnt;
3867 if (leftlen == 0) {
3868 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3869 return totcnt;
3870 }
3871 advoffset += cplen;
3872 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873
3874#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003875 /*
3876 * Display driver statistics for the board.
3877 */
3878 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003879 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003880 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
3881 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3882 totcnt += cnt;
3883 leftlen -= cnt;
3884 if (leftlen == 0) {
3885 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3886 return totcnt;
3887 }
3888 advoffset += cplen;
3889 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003891 /*
3892 * Display driver statistics for each target.
3893 */
3894 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
3895 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003896 cplen = asc_prt_target_stats(shost, tgt_id, cp,
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003897 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003898 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003899 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
3900 cplen);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003901 totcnt += cnt;
3902 leftlen -= cnt;
3903 if (leftlen == 0) {
3904 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3905 return totcnt;
3906 }
3907 advoffset += cplen;
3908 curbuf += cnt;
3909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910#endif /* ADVANSYS_STATS */
3911
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003912 /*
3913 * Display Asc Library dynamic configuration information
3914 * for the board.
3915 */
3916 cp = boardp->prtbuf;
3917 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003918 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003919 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003920 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003921 }
3922 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3923 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3924 totcnt += cnt;
3925 leftlen -= cnt;
3926 if (leftlen == 0) {
3927 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3928 return totcnt;
3929 }
3930 advoffset += cplen;
3931 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003933 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003935 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936}
3937#endif /* CONFIG_PROC_FS */
3938
3939/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 * advansys_info()
3941 *
3942 * Return suitable for printing on the console with the argument
3943 * adapter's configuration information.
3944 *
3945 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
3946 * otherwise the static 'info' array will be overrun.
3947 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003948static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003950 static char info[ASC_INFO_SIZE];
3951 asc_board_t *boardp;
3952 ASC_DVC_VAR *asc_dvc_varp;
3953 ADV_DVC_VAR *adv_dvc_varp;
3954 char *busname;
3955 int iolen;
3956 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003958 boardp = ASC_BOARDP(shost);
3959 if (ASC_NARROW_BOARD(boardp)) {
3960 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
3961 ASC_DBG(1, "advansys_info: begin\n");
3962 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
3963 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
3964 ASC_IS_ISAPNP) {
3965 busname = "ISA PnP";
3966 } else {
3967 busname = "ISA";
3968 }
3969 /* Don't reference 'shost->n_io_port'; It may be truncated. */
3970 sprintf(info,
3971 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
3972 ASC_VERSION, busname,
3973 (ulong)shost->io_port,
3974 (ulong)shost->io_port + boardp->asc_n_io_port -
3975 1, shost->irq, shost->dma_channel);
3976 } else {
3977 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
3978 busname = "VL";
3979 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
3980 busname = "EISA";
3981 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
3982 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
3983 == ASC_IS_PCI_ULTRA) {
3984 busname = "PCI Ultra";
3985 } else {
3986 busname = "PCI";
3987 }
3988 } else {
3989 busname = "?";
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003990 ASC_PRINT2("advansys_info: board %d: unknown "
3991 "bus type %d\n", boardp->id,
3992 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003993 }
3994 /* Don't reference 'shost->n_io_port'; It may be truncated. */
3995 sprintf(info,
3996 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003997 ASC_VERSION, busname, (ulong)shost->io_port,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003998 (ulong)shost->io_port + boardp->asc_n_io_port -
3999 1, shost->irq);
4000 }
4001 } else {
4002 /*
4003 * Wide Adapter Information
4004 *
4005 * Memory-mapped I/O is used instead of I/O space to access
4006 * the adapter, but display the I/O Port range. The Memory
4007 * I/O address is displayed through the driver /proc file.
4008 */
4009 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4010 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4011 iolen = ADV_3550_IOLEN;
4012 widename = "Ultra-Wide";
4013 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4014 iolen = ADV_38C0800_IOLEN;
4015 widename = "Ultra2-Wide";
4016 } else {
4017 iolen = ADV_38C1600_IOLEN;
4018 widename = "Ultra3-Wide";
4019 }
4020 sprintf(info,
4021 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
4022 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
4023 (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
4024 }
4025 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
4026 ASC_DBG(1, "advansys_info: end\n");
4027 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028}
4029
4030/*
4031 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
4032 *
4033 * This function always returns 0. Command return status is saved
4034 * in the 'scp' result field.
4035 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004036static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004037advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004039 struct Scsi_Host *shost;
4040 asc_board_t *boardp;
4041 ulong flags;
4042 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004044 shost = scp->device->host;
4045 boardp = ASC_BOARDP(shost);
4046 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004048 /* host_lock taken by mid-level prior to call but need to protect */
4049 /* against own ISR */
4050 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004052 /*
4053 * Block new commands while handling a reset or abort request.
4054 */
4055 if (boardp->flags & ASC_HOST_IN_RESET) {
4056 ASC_DBG1(1,
4057 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4058 (ulong)scp);
4059 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004061 /*
4062 * Add blocked requests to the board's 'done' queue. The queued
4063 * requests will be completed at the end of the abort or reset
4064 * handling.
4065 */
4066 asc_enqueue(&boardp->done, scp, ASC_BACK);
4067 spin_unlock_irqrestore(&boardp->lock, flags);
4068 return 0;
4069 }
4070
4071 /*
4072 * Attempt to execute any waiting commands for the board.
4073 */
4074 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4075 ASC_DBG(1,
4076 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4077 asc_execute_queue(&boardp->waiting);
4078 }
4079
4080 /*
4081 * Save the function pointer to Linux mid-level 'done' function
4082 * and attempt to execute the command.
4083 *
4084 * If ASC_NOERROR is returned the request has been added to the
4085 * board's 'active' queue and will be completed by the interrupt
4086 * handler.
4087 *
4088 * If ASC_BUSY is returned add the request to the board's per
4089 * target waiting list. This is the first time the request has
4090 * been tried. Add it to the back of the waiting list. It will be
4091 * retried later.
4092 *
4093 * If an error occurred, the request will have been placed on the
4094 * board's 'done' queue and must be completed before returning.
4095 */
4096 scp->scsi_done = done;
4097 switch (asc_execute_scsi_cmnd(scp)) {
4098 case ASC_NOERROR:
4099 break;
4100 case ASC_BUSY:
4101 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4102 break;
4103 case ASC_ERROR:
4104 default:
4105 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4106 /* Interrupts could be enabled here. */
4107 asc_scsi_done_list(done_scp);
4108 break;
4109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004112 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113}
4114
4115/*
4116 * advansys_reset()
4117 *
4118 * Reset the bus associated with the command 'scp'.
4119 *
4120 * This function runs its own thread. Interrupts must be blocked but
4121 * sleeping is allowed and no locking other than for host structures is
4122 * required. Returns SUCCESS or FAILED.
4123 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004124static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004126 struct Scsi_Host *shost;
4127 asc_board_t *boardp;
4128 ASC_DVC_VAR *asc_dvc_varp;
4129 ADV_DVC_VAR *adv_dvc_varp;
4130 ulong flags;
4131 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4132 struct scsi_cmnd *tscp, *new_last_scp;
4133 int status;
4134 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004136 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
4138#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004139 if (scp->device->host != NULL) {
4140 ASC_STATS(scp->device->host, reset);
4141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142#endif /* ADVANSYS_STATS */
4143
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004144 if ((shost = scp->device->host) == NULL) {
4145 scp->result = HOST_BYTE(DID_ERROR);
4146 return FAILED;
4147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004149 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004151 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4152 boardp->id);
4153 /*
4154 * Check for re-entrancy.
4155 */
4156 spin_lock_irqsave(&boardp->lock, flags);
4157 if (boardp->flags & ASC_HOST_IN_RESET) {
4158 spin_unlock_irqrestore(&boardp->lock, flags);
4159 return FAILED;
4160 }
4161 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004164 if (ASC_NARROW_BOARD(boardp)) {
4165 /*
4166 * Narrow Board
4167 */
4168 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004170 /*
4171 * Reset the chip and SCSI bus.
4172 */
4173 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4174 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004176 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4177 if (asc_dvc_varp->err_code) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004178 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4179 "error: 0x%x\n", boardp->id,
4180 asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004181 ret = FAILED;
4182 } else if (status) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004183 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4184 "warning: 0x%x\n", boardp->id, status);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004185 } else {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004186 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4187 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004190 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4191 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004193 } else {
4194 /*
4195 * Wide Board
4196 *
4197 * If the suggest reset bus flags are set, then reset the bus.
4198 * Otherwise only reset the device.
4199 */
4200 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004202 /*
4203 * Reset the target's SCSI bus.
4204 */
4205 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4206 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4207 case ASC_TRUE:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004208 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4209 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004210 break;
4211 case ASC_FALSE:
4212 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004213 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4214 "error.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004215 ret = FAILED;
4216 break;
4217 }
4218 spin_lock_irqsave(&boardp->lock, flags);
4219 (void)AdvISR(adv_dvc_varp);
4220 }
4221 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004223 /*
4224 * Dequeue all board 'done' requests. A pointer to the last request
4225 * is returned in 'last_scp'.
4226 */
4227 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004229 /*
4230 * Dequeue all board 'active' requests for all devices and set
4231 * the request status to DID_RESET. A pointer to the last request
4232 * is returned in 'last_scp'.
4233 */
4234 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004235 done_scp = asc_dequeue_list(&boardp->active, &last_scp,
4236 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004237 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4238 tscp->result = HOST_BYTE(DID_RESET);
4239 }
4240 } else {
4241 /* Append to 'done_scp' at the end with 'last_scp'. */
4242 ASC_ASSERT(last_scp != NULL);
4243 last_scp->host_scribble =
4244 (unsigned char *)asc_dequeue_list(&boardp->active,
4245 &new_last_scp,
4246 ASC_TID_ALL);
4247 if (new_last_scp != NULL) {
4248 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4249 for (tscp = REQPNEXT(last_scp); tscp;
4250 tscp = REQPNEXT(tscp)) {
4251 tscp->result = HOST_BYTE(DID_RESET);
4252 }
4253 last_scp = new_last_scp;
4254 }
4255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004257 /*
4258 * Dequeue all 'waiting' requests and set the request status
4259 * to DID_RESET.
4260 */
4261 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004262 done_scp = asc_dequeue_list(&boardp->waiting, &last_scp,
4263 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004264 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4265 tscp->result = HOST_BYTE(DID_RESET);
4266 }
4267 } else {
4268 /* Append to 'done_scp' at the end with 'last_scp'. */
4269 ASC_ASSERT(last_scp != NULL);
4270 last_scp->host_scribble =
4271 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4272 &new_last_scp,
4273 ASC_TID_ALL);
4274 if (new_last_scp != NULL) {
4275 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4276 for (tscp = REQPNEXT(last_scp); tscp;
4277 tscp = REQPNEXT(tscp)) {
4278 tscp->result = HOST_BYTE(DID_RESET);
4279 }
4280 last_scp = new_last_scp;
4281 }
4282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004284 /* Save the time of the most recently completed reset. */
4285 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004287 /* Clear reset flag. */
4288 boardp->flags &= ~ASC_HOST_IN_RESET;
4289 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004291 /*
4292 * Complete all the 'done_scp' requests.
4293 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004294 if (done_scp)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004295 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004297 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004299 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300}
4301
4302/*
4303 * advansys_biosparam()
4304 *
4305 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4306 * support is enabled for a drive.
4307 *
4308 * ip (information pointer) is an int array with the following definition:
4309 * ip[0]: heads
4310 * ip[1]: sectors
4311 * ip[2]: cylinders
4312 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004313static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004315 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004317 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004319 ASC_DBG(1, "advansys_biosparam: begin\n");
4320 ASC_STATS(sdev->host, biosparam);
4321 boardp = ASC_BOARDP(sdev->host);
4322 if (ASC_NARROW_BOARD(boardp)) {
4323 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4324 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4325 ip[0] = 255;
4326 ip[1] = 63;
4327 } else {
4328 ip[0] = 64;
4329 ip[1] = 32;
4330 }
4331 } else {
4332 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4333 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4334 ip[0] = 255;
4335 ip[1] = 63;
4336 } else {
4337 ip[0] = 64;
4338 ip[1] = 32;
4339 }
4340 }
4341 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4342 ASC_DBG(1, "advansys_biosparam: end\n");
4343 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344}
4345
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004346static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004347 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004349 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004351 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004352 .info = advansys_info,
4353 .queuecommand = advansys_queuecommand,
4354 .eh_bus_reset_handler = advansys_reset,
4355 .bios_param = advansys_biosparam,
4356 .slave_configure = advansys_slave_configure,
4357 /*
4358 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004359 * must be set. The flag will be cleared in advansys_board_found
4360 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004361 */
4362 .unchecked_isa_dma = 1,
4363 /*
4364 * All adapters controlled by this driver are capable of large
4365 * scatter-gather lists. According to the mid-level SCSI documentation
4366 * this obviates any performance gain provided by setting
4367 * 'use_clustering'. But empirically while CPU utilization is increased
4368 * by enabling clustering, I/O throughput increases as well.
4369 */
4370 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373/*
4374 * --- Miscellaneous Driver Functions
4375 */
4376
4377/*
4378 * First-level interrupt handler.
4379 *
4380 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4381 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4382 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4383 * to the AdvanSys driver which is for a device sharing an interrupt with
4384 * an AdvanSys adapter.
4385 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004386static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004388 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004389 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4390 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004391 struct Scsi_Host *shost = dev_id;
4392 asc_board_t *boardp = ASC_BOARDP(shost);
4393 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004395 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
4396 spin_lock_irqsave(&boardp->lock, flags);
4397 if (ASC_NARROW_BOARD(boardp)) {
4398 /*
4399 * Narrow Board
4400 */
4401 if (AscIsIntPending(shost->io_port)) {
4402 result = IRQ_HANDLED;
4403 ASC_STATS(shost, interrupt);
4404 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
4405 AscISR(&boardp->dvc_var.asc_dvc_var);
4406 }
4407 } else {
4408 /*
4409 * Wide Board
4410 */
4411 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4412 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4413 result = IRQ_HANDLED;
4414 ASC_STATS(shost, interrupt);
4415 }
4416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004418 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004419 * Start waiting requests and create a list of completed requests.
4420 *
4421 * If a reset request is being performed for the board, the reset
4422 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004423 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004424 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4425 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
4426 "last_scp 0x%p\n", done_scp, last_scp);
4427
4428 /* Start any waiting commands for the board. */
4429 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4430 ASC_DBG(1, "advansys_interrupt: before "
4431 "asc_execute_queue()\n");
4432 asc_execute_queue(&boardp->waiting);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004435 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004436 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004437 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004438 * 'done_scp' will always be NULL on the first iteration of
4439 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004440 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004441 if (done_scp == NULL) {
4442 done_scp = asc_dequeue_list(&boardp->done,
4443 &last_scp, ASC_TID_ALL);
4444 } else {
4445 ASC_ASSERT(last_scp != NULL);
4446 last_scp->host_scribble =
4447 (unsigned char *)asc_dequeue_list(&boardp->
4448 done,
4449 &new_last_scp,
4450 ASC_TID_ALL);
4451 if (new_last_scp != NULL) {
4452 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4453 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004454 }
4455 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004456 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004457 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004459 /*
4460 * If interrupts were enabled on entry, then they
4461 * are now enabled here.
4462 *
4463 * Complete all requests on the done list.
4464 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004466 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004468 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004469 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470}
4471
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004472static void
4473advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
4474{
4475 ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
4476 ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
4477
4478 if (sdev->lun == 0) {
4479 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
4480 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
4481 asc_dvc->init_sdtr |= tid_bit;
4482 } else {
4483 asc_dvc->init_sdtr &= ~tid_bit;
4484 }
4485
4486 if (orig_init_sdtr != asc_dvc->init_sdtr)
4487 AscAsyncFix(asc_dvc, sdev);
4488 }
4489
4490 if (sdev->tagged_supported) {
4491 if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
4492 if (sdev->lun == 0) {
4493 asc_dvc->cfg->can_tagged_qng |= tid_bit;
4494 asc_dvc->use_tagged_qng |= tid_bit;
4495 }
4496 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4497 asc_dvc->max_dvc_qng[sdev->id]);
4498 }
4499 } else {
4500 if (sdev->lun == 0) {
4501 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
4502 asc_dvc->use_tagged_qng &= ~tid_bit;
4503 }
4504 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4505 }
4506
4507 if ((sdev->lun == 0) &&
4508 (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
4509 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
4510 asc_dvc->cfg->disc_enable);
4511 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
4512 asc_dvc->use_tagged_qng);
4513 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
4514 asc_dvc->cfg->can_tagged_qng);
4515
4516 asc_dvc->max_dvc_qng[sdev->id] =
4517 asc_dvc->cfg->max_tag_qng[sdev->id];
4518 AscWriteLramByte(asc_dvc->iop_base,
4519 (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
4520 asc_dvc->max_dvc_qng[sdev->id]);
4521 }
4522}
4523
4524/*
4525 * Wide Transfers
4526 *
4527 * If the EEPROM enabled WDTR for the device and the device supports wide
4528 * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
4529 * write the new value to the microcode.
4530 */
4531static void
4532advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
4533{
4534 unsigned short cfg_word;
4535 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4536 if ((cfg_word & tidmask) != 0)
4537 return;
4538
4539 cfg_word |= tidmask;
4540 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4541
4542 /*
4543 * Clear the microcode SDTR and WDTR negotiation done indicators for
4544 * the target to cause it to negotiate with the new setting set above.
4545 * WDTR when accepted causes the target to enter asynchronous mode, so
4546 * SDTR must be negotiated.
4547 */
4548 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4549 cfg_word &= ~tidmask;
4550 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4551 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4552 cfg_word &= ~tidmask;
4553 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4554}
4555
4556/*
4557 * Synchronous Transfers
4558 *
4559 * If the EEPROM enabled SDTR for the device and the device
4560 * supports synchronous transfers, then turn on the device's
4561 * 'sdtr_able' bit. Write the new value to the microcode.
4562 */
4563static void
4564advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
4565{
4566 unsigned short cfg_word;
4567 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4568 if ((cfg_word & tidmask) != 0)
4569 return;
4570
4571 cfg_word |= tidmask;
4572 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4573
4574 /*
4575 * Clear the microcode "SDTR negotiation" done indicator for the
4576 * target to cause it to negotiate with the new setting set above.
4577 */
4578 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4579 cfg_word &= ~tidmask;
4580 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4581}
4582
4583/*
4584 * PPR (Parallel Protocol Request) Capable
4585 *
4586 * If the device supports DT mode, then it must be PPR capable.
4587 * The PPR message will be used in place of the SDTR and WDTR
4588 * messages to negotiate synchronous speed and offset, transfer
4589 * width, and protocol options.
4590 */
4591static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
4592 AdvPortAddr iop_base, unsigned short tidmask)
4593{
4594 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4595 adv_dvc->ppr_able |= tidmask;
4596 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4597}
4598
4599static void
4600advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
4601{
4602 AdvPortAddr iop_base = adv_dvc->iop_base;
4603 unsigned short tidmask = 1 << sdev->id;
4604
4605 if (sdev->lun == 0) {
4606 /*
4607 * Handle WDTR, SDTR, and Tag Queuing. If the feature
4608 * is enabled in the EEPROM and the device supports the
4609 * feature, then enable it in the microcode.
4610 */
4611
4612 if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
4613 advansys_wide_enable_wdtr(iop_base, tidmask);
4614 if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
4615 advansys_wide_enable_sdtr(iop_base, tidmask);
4616 if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
4617 advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
4618
4619 /*
4620 * Tag Queuing is disabled for the BIOS which runs in polled
4621 * mode and would see no benefit from Tag Queuing. Also by
4622 * disabling Tag Queuing in the BIOS devices with Tag Queuing
4623 * bugs will at least work with the BIOS.
4624 */
4625 if ((adv_dvc->tagqng_able & tidmask) &&
4626 sdev->tagged_supported) {
4627 unsigned short cfg_word;
4628 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
4629 cfg_word |= tidmask;
4630 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
4631 cfg_word);
4632 AdvWriteByteLram(iop_base,
4633 ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
4634 adv_dvc->max_dvc_qng);
4635 }
4636 }
4637
4638 if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
4639 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4640 adv_dvc->max_dvc_qng);
4641 } else {
4642 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4643 }
4644}
4645
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646/*
4647 * Set the number of commands to queue per device for the
4648 * specified host adapter.
4649 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004650static int advansys_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004652 asc_board_t *boardp = ASC_BOARDP(sdev->host);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004653 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004654
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004655 /*
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004656 * Save a pointer to the sdev and set its initial/maximum
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004657 * queue depth. Only save the pointer for a lun0 dev though.
4658 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004659 if (sdev->lun == 0)
4660 boardp->device[sdev->id] = sdev;
4661
4662 if (ASC_NARROW_BOARD(boardp))
4663 advansys_narrow_slave_configure(sdev,
4664 &boardp->dvc_var.asc_dvc_var);
4665 else
4666 advansys_wide_slave_configure(sdev,
4667 &boardp->dvc_var.adv_dvc_var);
4668
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004669 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670}
4671
4672/*
4673 * Complete all requests on the singly linked list pointed
4674 * to by 'scp'.
4675 *
4676 * Interrupts can be enabled on entry.
4677 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004678static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004680 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004682 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4683 while (scp != NULL) {
4684 asc_board_t *boardp;
4685 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004687 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4688 tscp = REQPNEXT(scp);
4689 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004691 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004693 if (ASC_NARROW_BOARD(boardp))
4694 dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
4695 else
4696 dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004698 if (scp->use_sg)
4699 dma_unmap_sg(dev,
4700 (struct scatterlist *)scp->request_buffer,
4701 scp->use_sg, scp->sc_data_direction);
4702 else if (scp->request_bufflen)
4703 dma_unmap_single(dev, scp->SCp.dma_handle,
4704 scp->request_bufflen,
4705 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004707 ASC_STATS(scp->device->host, done);
4708 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004710 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004712 scp = tscp;
4713 }
4714 ASC_DBG(2, "asc_scsi_done_list: done\n");
4715 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716}
4717
4718/*
4719 * Execute a single 'Scsi_Cmnd'.
4720 *
4721 * The function 'done' is called when the request has been completed.
4722 *
4723 * Scsi_Cmnd:
4724 *
4725 * host - board controlling device
4726 * device - device to send command
4727 * target - target of device
4728 * lun - lun of device
4729 * cmd_len - length of SCSI CDB
4730 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4731 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4732 *
4733 * if (use_sg == 0) {
4734 * request_buffer - buffer address for request
4735 * request_bufflen - length of request buffer
4736 * } else {
4737 * request_buffer - pointer to scatterlist structure
4738 * }
4739 *
4740 * sense_buffer - sense command buffer
4741 *
4742 * result (4 bytes of an int):
4743 * Byte Meaning
4744 * 0 SCSI Status Byte Code
4745 * 1 SCSI One Byte Message Code
4746 * 2 Host Error Code
4747 * 3 Mid-Level Error Code
4748 *
4749 * host driver fields:
4750 * SCp - Scsi_Pointer used for command processing status
4751 * scsi_done - used to save caller's done function
4752 * host_scribble - used for pointer to another struct scsi_cmnd
4753 *
4754 * If this function returns ASC_NOERROR the request has been enqueued
4755 * on the board's 'active' queue and will be completed from the
4756 * interrupt handler.
4757 *
4758 * If this function returns ASC_NOERROR the request has been enqueued
4759 * on the board's 'done' queue and must be completed by the caller.
4760 *
4761 * If ASC_BUSY is returned the request will be enqueued by the
4762 * caller on the target's waiting queue and re-tried later.
4763 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004764static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004766 asc_board_t *boardp;
4767 ASC_DVC_VAR *asc_dvc_varp;
4768 ADV_DVC_VAR *adv_dvc_varp;
4769 ADV_SCSI_REQ_Q *adv_scsiqp;
4770 struct scsi_device *device;
4771 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004773 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4774 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004776 boardp = ASC_BOARDP(scp->device->host);
4777 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004779 if (ASC_NARROW_BOARD(boardp)) {
4780 /*
4781 * Build and execute Narrow Board request.
4782 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004784 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004786 /*
4787 * Build Asc Library request structure using the
4788 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4789 *
4790 * If an error is returned, then the request has been
4791 * queued on the board done queue. It will be completed
4792 * by the caller.
4793 *
4794 * asc_build_req() can not return ASC_BUSY.
4795 */
4796 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4797 ASC_STATS(scp->device->host, build_error);
4798 return ASC_ERROR;
4799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004801 /*
4802 * Execute the command. If there is no error, add the command
4803 * to the active queue.
4804 */
4805 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4806 case ASC_NOERROR:
4807 ASC_STATS(scp->device->host, exe_noerror);
4808 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004809 * Increment monotonically increasing per device
4810 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004811 */
4812 boardp->reqcnt[scp->device->id]++;
4813 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004814 ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), "
4815 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004816 break;
4817 case ASC_BUSY:
4818 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004819 * Caller will enqueue request on the target's waiting
4820 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004821 */
4822 ASC_STATS(scp->device->host, exe_busy);
4823 break;
4824 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004825 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4826 "AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4827 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004828 ASC_STATS(scp->device->host, exe_error);
4829 scp->result = HOST_BYTE(DID_ERROR);
4830 asc_enqueue(&boardp->done, scp, ASC_BACK);
4831 break;
4832 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004833 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4834 "AscExeScsiQueue() unknown, err_code 0x%x\n",
4835 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004836 ASC_STATS(scp->device->host, exe_unknown);
4837 scp->result = HOST_BYTE(DID_ERROR);
4838 asc_enqueue(&boardp->done, scp, ASC_BACK);
4839 break;
4840 }
4841 } else {
4842 /*
4843 * Build and execute Wide Board request.
4844 */
4845 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004847 /*
4848 * Build and get a pointer to an Adv Library request structure.
4849 *
4850 * If the request is successfully built then send it below,
4851 * otherwise return with an error.
4852 */
4853 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4854 case ASC_NOERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004855 ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req "
4856 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004857 break;
4858 case ASC_BUSY:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004859 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4860 "ASC_BUSY\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004861 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004862 * If busy is returned the request has not been
4863 * enqueued. It will be enqueued by the caller on the
4864 * target's waiting queue and retried later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004865 *
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004866 * The asc_stats fields 'adv_build_noreq' and
4867 * 'adv_build_nosg' count wide board busy conditions.
4868 * They are updated in adv_build_req and
4869 * adv_get_sglist, respectively.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004870 */
4871 return ASC_BUSY;
4872 case ASC_ERROR:
4873 /*
4874 * If an error is returned, then the request has been
4875 * queued on the board done queue. It will be completed
4876 * by the caller.
4877 */
4878 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004879 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4880 "ASC_ERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004881 ASC_STATS(scp->device->host, build_error);
4882 return ASC_ERROR;
4883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004885 /*
4886 * Execute the command. If there is no error, add the command
4887 * to the active queue.
4888 */
4889 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
4890 case ASC_NOERROR:
4891 ASC_STATS(scp->device->host, exe_noerror);
4892 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004893 * Increment monotonically increasing per device
4894 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004895 */
4896 boardp->reqcnt[scp->device->id]++;
4897 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004898 ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), "
4899 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004900 break;
4901 case ASC_BUSY:
4902 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004903 * Caller will enqueue request on the target's waiting
4904 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004905 */
4906 ASC_STATS(scp->device->host, exe_busy);
4907 break;
4908 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004909 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4910 "AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4911 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004912 ASC_STATS(scp->device->host, exe_error);
4913 scp->result = HOST_BYTE(DID_ERROR);
4914 asc_enqueue(&boardp->done, scp, ASC_BACK);
4915 break;
4916 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004917 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4918 "AdvExeScsiQueue() unknown, err_code 0x%x\n",
4919 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004920 ASC_STATS(scp->device->host, exe_unknown);
4921 scp->result = HOST_BYTE(DID_ERROR);
4922 asc_enqueue(&boardp->done, scp, ASC_BACK);
4923 break;
4924 }
4925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004927 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
4928 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929}
4930
4931/*
4932 * Build a request structure for the Asc Library (Narrow Board).
4933 *
4934 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
4935 * used to build the request.
4936 *
4937 * If an error occurs, then queue the request on the board done
4938 * queue and return ASC_ERROR.
4939 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004940static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004942 struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004944 /*
4945 * Mutually exclusive access is required to 'asc_scsi_q' and
4946 * 'asc_sg_head' until after the request is started.
4947 */
4948 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004950 /*
4951 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
4952 */
4953 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004955 /*
4956 * Build the ASC_SCSI_Q request.
4957 *
4958 * For narrow boards a CDB length maximum of 12 bytes
4959 * is supported.
4960 */
4961 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004962 ASC_PRINT3("asc_build_req: board %d: cmd_len %d > "
4963 "ASC_MAX_CDB_LEN %d\n", boardp->id, scp->cmd_len,
4964 ASC_MAX_CDB_LEN);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004965 scp->result = HOST_BYTE(DID_ERROR);
4966 asc_enqueue(&boardp->done, scp, ASC_BACK);
4967 return ASC_ERROR;
4968 }
4969 asc_scsi_q.cdbptr = &scp->cmnd[0];
4970 asc_scsi_q.q2.cdb_len = scp->cmd_len;
4971 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
4972 asc_scsi_q.q1.target_lun = scp->device->lun;
4973 asc_scsi_q.q2.target_ix =
4974 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
4975 asc_scsi_q.q1.sense_addr =
4976 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4977 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004979 /*
4980 * If there are any outstanding requests for the current target,
4981 * then every 255th request send an ORDERED request. This heuristic
4982 * tries to retain the benefit of request sorting while preventing
4983 * request starvation. 255 is the max number of tags or pending commands
4984 * a device may have outstanding.
4985 *
4986 * The request count is incremented below for every successfully
4987 * started request.
4988 *
4989 */
4990 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
4991 (boardp->reqcnt[scp->device->id] % 255) == 0) {
4992 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
4993 } else {
4994 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
4995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004997 /*
4998 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
4999 * buffer command.
5000 */
5001 if (scp->use_sg == 0) {
5002 /*
5003 * CDB request of single contiguous buffer.
5004 */
5005 ASC_STATS(scp->device->host, cont_cnt);
5006 scp->SCp.dma_handle = scp->request_bufflen ?
5007 dma_map_single(dev, scp->request_buffer,
5008 scp->request_bufflen,
5009 scp->sc_data_direction) : 0;
5010 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
5011 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
5012 ASC_STATS_ADD(scp->device->host, cont_xfer,
5013 ASC_CEILING(scp->request_bufflen, 512));
5014 asc_scsi_q.q1.sg_queue_cnt = 0;
5015 asc_scsi_q.sg_head = NULL;
5016 } else {
5017 /*
5018 * CDB scatter-gather request list.
5019 */
5020 int sgcnt;
5021 int use_sg;
5022 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005024 slp = (struct scatterlist *)scp->request_buffer;
5025 use_sg =
5026 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005028 if (use_sg > scp->device->host->sg_tablesize) {
5029 ASC_PRINT3
5030 ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
5031 boardp->id, use_sg,
5032 scp->device->host->sg_tablesize);
5033 dma_unmap_sg(dev, slp, scp->use_sg,
5034 scp->sc_data_direction);
5035 scp->result = HOST_BYTE(DID_ERROR);
5036 asc_enqueue(&boardp->done, scp, ASC_BACK);
5037 return ASC_ERROR;
5038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005040 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005042 /*
5043 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
5044 * structure to point to it.
5045 */
5046 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005048 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5049 asc_scsi_q.sg_head = &asc_sg_head;
5050 asc_scsi_q.q1.data_cnt = 0;
5051 asc_scsi_q.q1.data_addr = 0;
5052 /* This is a byte value, otherwise it would need to be swapped. */
5053 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5054 ASC_STATS_ADD(scp->device->host, sg_elem,
5055 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005057 /*
5058 * Convert scatter-gather list into ASC_SG_HEAD list.
5059 */
5060 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5061 asc_sg_head.sg_list[sgcnt].addr =
5062 cpu_to_le32(sg_dma_address(slp));
5063 asc_sg_head.sg_list[sgcnt].bytes =
5064 cpu_to_le32(sg_dma_len(slp));
5065 ASC_STATS_ADD(scp->device->host, sg_xfer,
5066 ASC_CEILING(sg_dma_len(slp), 512));
5067 }
5068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005070 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5071 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005073 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074}
5075
5076/*
5077 * Build a request structure for the Adv Library (Wide Board).
5078 *
5079 * If an adv_req_t can not be allocated to issue the request,
5080 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5081 *
5082 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5083 * microcode for DMA addresses or math operations are byte swapped
5084 * to little-endian order.
5085 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005086static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005088 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005090 adv_req_t *reqp;
5091 ADV_SCSI_REQ_Q *scsiqp;
5092 int i;
5093 int ret;
5094 struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005096 /*
5097 * Allocate an adv_req_t structure from the board to execute
5098 * the command.
5099 */
5100 if (boardp->adv_reqp == NULL) {
5101 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5102 ASC_STATS(scp->device->host, adv_build_noreq);
5103 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005105 reqp = boardp->adv_reqp;
5106 boardp->adv_reqp = reqp->next_reqp;
5107 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005110 /*
5111 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5112 */
5113 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005115 /*
5116 * Initialize the structure.
5117 */
5118 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005120 /*
5121 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5122 */
5123 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005125 /*
5126 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5127 */
5128 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005130 /*
5131 * Build the ADV_SCSI_REQ_Q request.
5132 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005134 /*
5135 * Set CDB length and copy it to the request structure.
5136 * For wide boards a CDB length maximum of 16 bytes
5137 * is supported.
5138 */
5139 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5140 ASC_PRINT3
5141 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5142 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5143 scp->result = HOST_BYTE(DID_ERROR);
5144 asc_enqueue(&boardp->done, scp, ASC_BACK);
5145 return ASC_ERROR;
5146 }
5147 scsiqp->cdb_len = scp->cmd_len;
5148 /* Copy first 12 CDB bytes to cdb[]. */
5149 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5150 scsiqp->cdb[i] = scp->cmnd[i];
5151 }
5152 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5153 for (; i < scp->cmd_len; i++) {
5154 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005157 scsiqp->target_id = scp->device->id;
5158 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005160 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5161 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005163 /*
5164 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5165 * buffer command.
5166 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005168 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5169 scsiqp->vdata_addr = scp->request_buffer;
5170 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5171
5172 if (scp->use_sg == 0) {
5173 /*
5174 * CDB request of single contiguous buffer.
5175 */
5176 reqp->sgblkp = NULL;
5177 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5178 if (scp->request_bufflen) {
5179 scsiqp->vdata_addr = scp->request_buffer;
5180 scp->SCp.dma_handle =
5181 dma_map_single(dev, scp->request_buffer,
5182 scp->request_bufflen,
5183 scp->sc_data_direction);
5184 } else {
5185 scsiqp->vdata_addr = NULL;
5186 scp->SCp.dma_handle = 0;
5187 }
5188 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5189 scsiqp->sg_list_ptr = NULL;
5190 scsiqp->sg_real_addr = 0;
5191 ASC_STATS(scp->device->host, cont_cnt);
5192 ASC_STATS_ADD(scp->device->host, cont_xfer,
5193 ASC_CEILING(scp->request_bufflen, 512));
5194 } else {
5195 /*
5196 * CDB scatter-gather request list.
5197 */
5198 struct scatterlist *slp;
5199 int use_sg;
5200
5201 slp = (struct scatterlist *)scp->request_buffer;
5202 use_sg =
5203 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
5204
5205 if (use_sg > ADV_MAX_SG_LIST) {
5206 ASC_PRINT3
5207 ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
5208 boardp->id, use_sg,
5209 scp->device->host->sg_tablesize);
5210 dma_unmap_sg(dev, slp, scp->use_sg,
5211 scp->sc_data_direction);
5212 scp->result = HOST_BYTE(DID_ERROR);
5213 asc_enqueue(&boardp->done, scp, ASC_BACK);
5214
5215 /*
5216 * Free the 'adv_req_t' structure by adding it back to the
5217 * board free list.
5218 */
5219 reqp->next_reqp = boardp->adv_reqp;
5220 boardp->adv_reqp = reqp;
5221
5222 return ASC_ERROR;
5223 }
5224
5225 if ((ret =
5226 adv_get_sglist(boardp, reqp, scp,
5227 use_sg)) != ADV_SUCCESS) {
5228 /*
5229 * Free the adv_req_t structure by adding it back to the
5230 * board free list.
5231 */
5232 reqp->next_reqp = boardp->adv_reqp;
5233 boardp->adv_reqp = reqp;
5234
5235 return ret;
5236 }
5237
5238 ASC_STATS(scp->device->host, sg_cnt);
5239 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5240 }
5241
5242 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5243 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5244
5245 *adv_scsiqpp = scsiqp;
5246
5247 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248}
5249
5250/*
5251 * Build scatter-gather list for Adv Library (Wide Board).
5252 *
5253 * Additional ADV_SG_BLOCK structures will need to be allocated
5254 * if the total number of scatter-gather elements exceeds
5255 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5256 * assumed to be physically contiguous.
5257 *
5258 * Return:
5259 * ADV_SUCCESS(1) - SG List successfully created
5260 * ADV_ERROR(-1) - SG List creation failed
5261 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005262static int
5263adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5264 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005266 adv_sgblk_t *sgblkp;
5267 ADV_SCSI_REQ_Q *scsiqp;
5268 struct scatterlist *slp;
5269 int sg_elem_cnt;
5270 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5271 ADV_PADDR sg_block_paddr;
5272 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005274 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5275 slp = (struct scatterlist *)scp->request_buffer;
5276 sg_elem_cnt = use_sg;
5277 prev_sg_block = NULL;
5278 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005280 do {
5281 /*
5282 * Allocate a 'adv_sgblk_t' structure from the board free
5283 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5284 * (15) scatter-gather elements.
5285 */
5286 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5287 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5288 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005290 /*
5291 * Allocation failed. Free 'adv_sgblk_t' structures already
5292 * allocated for the request.
5293 */
5294 while ((sgblkp = reqp->sgblkp) != NULL) {
5295 /* Remove 'sgblkp' from the request list. */
5296 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005298 /* Add 'sgblkp' to the board free list. */
5299 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5300 boardp->adv_sgblkp = sgblkp;
5301 }
5302 return ASC_BUSY;
5303 } else {
5304 /* Complete 'adv_sgblk_t' board allocation. */
5305 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5306 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005308 /*
5309 * Get 8 byte aligned virtual and physical addresses for
5310 * the allocated ADV_SG_BLOCK structure.
5311 */
5312 sg_block =
5313 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5314 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005316 /*
5317 * Check if this is the first 'adv_sgblk_t' for the request.
5318 */
5319 if (reqp->sgblkp == NULL) {
5320 /* Request's first scatter-gather block. */
5321 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005323 /*
5324 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5325 * address pointers.
5326 */
5327 scsiqp->sg_list_ptr = sg_block;
5328 scsiqp->sg_real_addr =
5329 cpu_to_le32(sg_block_paddr);
5330 } else {
5331 /* Request's second or later scatter-gather block. */
5332 sgblkp->next_sgblkp = reqp->sgblkp;
5333 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005335 /*
5336 * Point the previous ADV_SG_BLOCK structure to
5337 * the newly allocated ADV_SG_BLOCK structure.
5338 */
5339 ASC_ASSERT(prev_sg_block != NULL);
5340 prev_sg_block->sg_ptr =
5341 cpu_to_le32(sg_block_paddr);
5342 }
5343 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005345 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5346 sg_block->sg_list[i].sg_addr =
5347 cpu_to_le32(sg_dma_address(slp));
5348 sg_block->sg_list[i].sg_count =
5349 cpu_to_le32(sg_dma_len(slp));
5350 ASC_STATS_ADD(scp->device->host, sg_xfer,
5351 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005353 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5354 sg_block->sg_cnt = i + 1;
5355 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5356 return ADV_SUCCESS;
5357 }
5358 slp++;
5359 }
5360 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5361 prev_sg_block = sg_block;
5362 }
5363 while (1);
5364 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365}
5366
5367/*
5368 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5369 *
5370 * Interrupt callback function for the Narrow SCSI Asc Library.
5371 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005372static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005374 asc_board_t *boardp;
5375 struct scsi_cmnd *scp;
5376 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005378 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5379 (ulong)asc_dvc_varp, (ulong)qdonep);
5380 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005382 /*
5383 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5384 * command that has been completed.
5385 */
5386 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5387 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005389 if (scp == NULL) {
5390 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5391 return;
5392 }
5393 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005395 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005396 ASC_STATS(shost, callback);
5397 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005399 /*
5400 * If the request isn't found on the active queue, it may
5401 * have been removed to handle a reset request.
5402 * Display a message and return.
5403 */
5404 boardp = ASC_BOARDP(shost);
5405 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5406 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5407 ASC_PRINT2
5408 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5409 boardp->id, (ulong)scp);
5410 return;
5411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005413 /*
5414 * 'qdonep' contains the command's ending status.
5415 */
5416 switch (qdonep->d3.done_stat) {
5417 case QD_NO_ERROR:
5418 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5419 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005421 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005422 * Check for an underrun condition.
5423 *
5424 * If there was no error and an underrun condition, then
Matthew Wilcox47d853c2007-07-26 11:41:33 -04005425 * return the number of underrun bytes.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005426 */
5427 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5428 qdonep->remain_bytes <= scp->request_bufflen) {
5429 ASC_DBG1(1,
5430 "asc_isr_callback: underrun condition %u bytes\n",
5431 (unsigned)qdonep->remain_bytes);
5432 scp->resid = qdonep->remain_bytes;
5433 }
5434 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005436 case QD_WITH_ERROR:
5437 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5438 switch (qdonep->d3.host_stat) {
5439 case QHSTA_NO_ERROR:
5440 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5441 ASC_DBG(2,
5442 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5443 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5444 sizeof(scp->sense_buffer));
5445 /*
5446 * Note: The 'status_byte()' macro used by target drivers
5447 * defined in scsi.h shifts the status byte returned by
5448 * host drivers right by 1 bit. This is why target drivers
5449 * also use right shifted status byte definitions. For
5450 * instance target drivers use CHECK_CONDITION, defined to
5451 * 0x1, instead of the SCSI defined check condition value
5452 * of 0x2. Host drivers are supposed to return the status
5453 * byte as it is defined by SCSI.
5454 */
5455 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5456 STATUS_BYTE(qdonep->d3.scsi_stat);
5457 } else {
5458 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5459 }
5460 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005462 default:
5463 /* QHSTA error occurred */
5464 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5465 qdonep->d3.host_stat);
5466 scp->result = HOST_BYTE(DID_BAD_TARGET);
5467 break;
5468 }
5469 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005471 case QD_ABORTED_BY_HOST:
5472 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5473 scp->result =
5474 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5475 scsi_msg) |
5476 STATUS_BYTE(qdonep->d3.scsi_stat);
5477 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005479 default:
5480 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5481 qdonep->d3.done_stat);
5482 scp->result =
5483 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5484 scsi_msg) |
5485 STATUS_BYTE(qdonep->d3.scsi_stat);
5486 break;
5487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005489 /*
5490 * If the 'init_tidmask' bit isn't already set for the target and the
5491 * current request finished normally, then set the bit for the target
5492 * to indicate that a device is present.
5493 */
5494 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5495 qdonep->d3.done_stat == QD_NO_ERROR &&
5496 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5497 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005500 /*
5501 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5502 * function, add the command to the end of the board's done queue.
5503 * The done function for the command will be called from
5504 * advansys_interrupt().
5505 */
5506 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005508 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509}
5510
5511/*
5512 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5513 *
5514 * Callback function for the Wide SCSI Adv Library.
5515 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005516static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005518 asc_board_t *boardp;
5519 adv_req_t *reqp;
5520 adv_sgblk_t *sgblkp;
5521 struct scsi_cmnd *scp;
5522 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005523 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005525 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5526 (ulong)adv_dvc_varp, (ulong)scsiqp);
5527 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005529 /*
5530 * Get the adv_req_t structure for the command that has been
5531 * completed. The adv_req_t structure actually contains the
5532 * completed ADV_SCSI_REQ_Q structure.
5533 */
5534 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5535 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5536 if (reqp == NULL) {
5537 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5538 return;
5539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005540
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005541 /*
5542 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5543 * command that has been completed.
5544 *
5545 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5546 * if any, are dropped, because a board structure pointer can not be
5547 * determined.
5548 */
5549 scp = reqp->cmndp;
5550 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5551 if (scp == NULL) {
5552 ASC_PRINT
5553 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5554 return;
5555 }
5556 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005558 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005559 ASC_STATS(shost, callback);
5560 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005562 /*
5563 * If the request isn't found on the active queue, it may have been
5564 * removed to handle a reset request. Display a message and return.
5565 *
5566 * Note: Because the structure may still be in use don't attempt
5567 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5568 */
5569 boardp = ASC_BOARDP(shost);
5570 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5571 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5572 ASC_PRINT2
5573 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5574 boardp->id, (ulong)scp);
5575 return;
5576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005578 /*
5579 * 'done_status' contains the command's ending status.
5580 */
5581 switch (scsiqp->done_status) {
5582 case QD_NO_ERROR:
5583 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5584 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005586 /*
5587 * Check for an underrun condition.
5588 *
5589 * If there was no error and an underrun condition, then
5590 * then return the number of underrun bytes.
5591 */
5592 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5593 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5594 resid_cnt <= scp->request_bufflen) {
5595 ASC_DBG1(1,
5596 "adv_isr_callback: underrun condition %lu bytes\n",
5597 (ulong)resid_cnt);
5598 scp->resid = resid_cnt;
5599 }
5600 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005602 case QD_WITH_ERROR:
5603 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5604 switch (scsiqp->host_status) {
5605 case QHSTA_NO_ERROR:
5606 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5607 ASC_DBG(2,
5608 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5609 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5610 sizeof(scp->sense_buffer));
5611 /*
5612 * Note: The 'status_byte()' macro used by target drivers
5613 * defined in scsi.h shifts the status byte returned by
5614 * host drivers right by 1 bit. This is why target drivers
5615 * also use right shifted status byte definitions. For
5616 * instance target drivers use CHECK_CONDITION, defined to
5617 * 0x1, instead of the SCSI defined check condition value
5618 * of 0x2. Host drivers are supposed to return the status
5619 * byte as it is defined by SCSI.
5620 */
5621 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5622 STATUS_BYTE(scsiqp->scsi_status);
5623 } else {
5624 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5625 }
5626 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005628 default:
5629 /* Some other QHSTA error occurred. */
5630 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5631 scsiqp->host_status);
5632 scp->result = HOST_BYTE(DID_BAD_TARGET);
5633 break;
5634 }
5635 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005637 case QD_ABORTED_BY_HOST:
5638 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5639 scp->result =
5640 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5641 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005643 default:
5644 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5645 scsiqp->done_status);
5646 scp->result =
5647 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5648 break;
5649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005651 /*
5652 * If the 'init_tidmask' bit isn't already set for the target and the
5653 * current request finished normally, then set the bit for the target
5654 * to indicate that a device is present.
5655 */
5656 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5657 scsiqp->done_status == QD_NO_ERROR &&
5658 scsiqp->host_status == QHSTA_NO_ERROR) {
5659 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005662 /*
5663 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5664 * function, add the command to the end of the board's done queue.
5665 * The done function for the command will be called from
5666 * advansys_interrupt().
5667 */
5668 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005670 /*
5671 * Free all 'adv_sgblk_t' structures allocated for the request.
5672 */
5673 while ((sgblkp = reqp->sgblkp) != NULL) {
5674 /* Remove 'sgblkp' from the request list. */
5675 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005677 /* Add 'sgblkp' to the board free list. */
5678 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5679 boardp->adv_sgblkp = sgblkp;
5680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005682 /*
5683 * Free the adv_req_t structure used with the command by adding
5684 * it back to the board free list.
5685 */
5686 reqp->next_reqp = boardp->adv_reqp;
5687 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005689 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005691 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692}
5693
5694/*
5695 * adv_async_callback() - Adv Library asynchronous event callback function.
5696 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005697static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005699 switch (code) {
5700 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5701 /*
5702 * The firmware detected a SCSI Bus reset.
5703 */
5704 ASC_DBG(0,
5705 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5706 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005708 case ADV_ASYNC_RDMA_FAILURE:
5709 /*
5710 * Handle RDMA failure by resetting the SCSI Bus and
5711 * possibly the chip if it is unresponsive. Log the error
5712 * with a unique code.
5713 */
5714 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5715 AdvResetChipAndSB(adv_dvc_varp);
5716 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005718 case ADV_HOST_SCSI_BUS_RESET:
5719 /*
5720 * Host generated SCSI bus reset occurred.
5721 */
5722 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5723 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005725 default:
5726 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5727 break;
5728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729}
5730
5731/*
5732 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5733 * to indicate a command is queued for the device.
5734 *
5735 * 'flag' may be either ASC_FRONT or ASC_BACK.
5736 *
5737 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5738 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005739static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005741 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005743 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5744 (ulong)ascq, (ulong)reqp, flag);
5745 ASC_ASSERT(reqp != NULL);
5746 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5747 tid = REQPTID(reqp);
5748 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5749 if (flag == ASC_FRONT) {
5750 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5751 ascq->q_first[tid] = reqp;
5752 /* If the queue was empty, set the last pointer. */
5753 if (ascq->q_last[tid] == NULL) {
5754 ascq->q_last[tid] = reqp;
5755 }
5756 } else { /* ASC_BACK */
5757 if (ascq->q_last[tid] != NULL) {
5758 ascq->q_last[tid]->host_scribble =
5759 (unsigned char *)reqp;
5760 }
5761 ascq->q_last[tid] = reqp;
5762 reqp->host_scribble = NULL;
5763 /* If the queue was empty, set the first pointer. */
5764 if (ascq->q_first[tid] == NULL) {
5765 ascq->q_first[tid] = reqp;
5766 }
5767 }
5768 /* The queue has at least one entry, set its bit. */
5769 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005770#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005771 /* Maintain request queue statistics. */
5772 ascq->q_tot_cnt[tid]++;
5773 ascq->q_cur_cnt[tid]++;
5774 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5775 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5776 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5777 tid, ascq->q_max_cnt[tid]);
5778 }
5779 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005781 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5782 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005783}
5784
5785/*
5786 * Return first queued 'REQP' on the specified queue for
5787 * the specified target device. Clear the 'tidmask' bit for
5788 * the device if no more commands are left queued for it.
5789 *
5790 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5791 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005792static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005794 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005796 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5797 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5798 if ((reqp = ascq->q_first[tid]) != NULL) {
5799 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5800 ascq->q_first[tid] = REQPNEXT(reqp);
5801 /* If the queue is empty, clear its bit and the last pointer. */
5802 if (ascq->q_first[tid] == NULL) {
5803 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5804 ASC_ASSERT(ascq->q_last[tid] == reqp);
5805 ascq->q_last[tid] = NULL;
5806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005808 /* Maintain request queue statistics. */
5809 ascq->q_cur_cnt[tid]--;
5810 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
5811 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005813 }
5814 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
5815 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005816}
5817
5818/*
5819 * Return a pointer to a singly linked list of all the requests queued
5820 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
5821 *
5822 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
5823 * the last request returned in the singly linked list.
5824 *
5825 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
5826 * then all queued requests are concatenated into one list and
5827 * returned.
5828 *
5829 * Note: If 'lastpp' is used to append a new list to the end of
5830 * an old list, only change the old list last pointer if '*lastpp'
5831 * (or the function return value) is not NULL, i.e. use a temporary
5832 * variable for 'lastpp' and check its value after the function return
5833 * before assigning it to the list last pointer.
5834 *
5835 * Unfortunately collecting queuing time statistics adds overhead to
5836 * the function that isn't inherent to the function's algorithm.
5837 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005838static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005840 REQP firstp, lastp;
5841 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005843 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5844 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005846 /*
5847 * If 'tid' is not ASC_TID_ALL, return requests only for
5848 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
5849 * requests for all tids.
5850 */
5851 if (tid != ASC_TID_ALL) {
5852 /* Return all requests for the specified 'tid'. */
5853 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
5854 /* List is empty; Set first and last return pointers to NULL. */
5855 firstp = lastp = NULL;
5856 } else {
5857 firstp = ascq->q_first[tid];
5858 lastp = ascq->q_last[tid];
5859 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
5860 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005862 {
5863 REQP reqp;
5864 ascq->q_cur_cnt[tid] = 0;
5865 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5866 REQTIMESTAT("asc_dequeue_list", ascq,
5867 reqp, tid);
5868 }
5869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005871 }
5872 } else {
5873 /* Return all requests for all tids. */
5874 firstp = lastp = NULL;
5875 for (i = 0; i <= ADV_MAX_TID; i++) {
5876 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
5877 if (firstp == NULL) {
5878 firstp = ascq->q_first[i];
5879 lastp = ascq->q_last[i];
5880 } else {
5881 ASC_ASSERT(lastp != NULL);
5882 lastp->host_scribble =
5883 (unsigned char *)ascq->q_first[i];
5884 lastp = ascq->q_last[i];
5885 }
5886 ascq->q_first[i] = ascq->q_last[i] = NULL;
5887 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005889 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005891 }
5892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005893#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005894 {
5895 REQP reqp;
5896 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5897 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
5898 reqp->device->id);
5899 }
5900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005902 }
5903 if (lastpp) {
5904 *lastpp = lastp;
5905 }
5906 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
5907 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908}
5909
5910/*
5911 * Remove the specified 'REQP' from the specified queue for
5912 * the specified target device. Clear the 'tidmask' bit for the
5913 * device if no more commands are left queued for it.
5914 *
5915 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
5916 *
5917 * Return ASC_TRUE if the command was found and removed,
5918 * otherwise return ASC_FALSE.
5919 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005920static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005922 REQP currp, prevp;
5923 int tid;
5924 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005926 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
5927 (ulong)ascq, (ulong)reqp);
5928 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005930 tid = REQPTID(reqp);
5931 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005933 /*
5934 * Handle the common case of 'reqp' being the first
5935 * entry on the queue.
5936 */
5937 if (reqp == ascq->q_first[tid]) {
5938 ret = ASC_TRUE;
5939 ascq->q_first[tid] = REQPNEXT(reqp);
5940 /* If the queue is now empty, clear its bit and the last pointer. */
5941 if (ascq->q_first[tid] == NULL) {
5942 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5943 ASC_ASSERT(ascq->q_last[tid] == reqp);
5944 ascq->q_last[tid] = NULL;
5945 }
5946 } else if (ascq->q_first[tid] != NULL) {
5947 ASC_ASSERT(ascq->q_last[tid] != NULL);
5948 /*
5949 * Because the case of 'reqp' being the first entry has been
5950 * handled above and it is known the queue is not empty, if
5951 * 'reqp' is found on the queue it is guaranteed the queue will
5952 * not become empty and that 'q_first[tid]' will not be changed.
5953 *
5954 * Set 'prevp' to the first entry, 'currp' to the second entry,
5955 * and search for 'reqp'.
5956 */
5957 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
5958 currp; prevp = currp, currp = REQPNEXT(currp)) {
5959 if (currp == reqp) {
5960 ret = ASC_TRUE;
5961 prevp->host_scribble =
5962 (unsigned char *)REQPNEXT(currp);
5963 reqp->host_scribble = NULL;
5964 if (ascq->q_last[tid] == reqp) {
5965 ascq->q_last[tid] = prevp;
5966 }
5967 break;
5968 }
5969 }
5970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005972 /* Maintain request queue statistics. */
5973 if (ret == ASC_TRUE) {
5974 ascq->q_cur_cnt[tid]--;
5975 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
5976 }
5977 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005979 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
5980 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981}
5982
5983/*
5984 * Execute as many queued requests as possible for the specified queue.
5985 *
5986 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
5987 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005988static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005990 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
5991 REQP reqp;
5992 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005994 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
5995 /*
5996 * Execute queued commands for devices attached to
5997 * the current board in round-robin fashion.
5998 */
5999 scan_tidmask = ascq->q_tidmask;
6000 do {
6001 for (i = 0; i <= ADV_MAX_TID; i++) {
6002 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
6003 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
6004 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6005 } else
6006 if (asc_execute_scsi_cmnd
6007 ((struct scsi_cmnd *)reqp)
6008 == ASC_BUSY) {
6009 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6010 /*
6011 * The request returned ASC_BUSY. Enqueue at the front of
6012 * target's waiting list to maintain correct ordering.
6013 */
6014 asc_enqueue(ascq, reqp, ASC_FRONT);
6015 }
6016 }
6017 }
6018 } while (scan_tidmask);
6019 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020}
6021
6022#ifdef CONFIG_PROC_FS
6023/*
6024 * asc_prt_board_devices()
6025 *
6026 * Print driver information for devices attached to the board.
6027 *
6028 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6029 * cf. asc_prt_line().
6030 *
6031 * Return the number of characters copied into 'cp'. No more than
6032 * 'cplen' characters will be copied to 'cp'.
6033 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006034static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006036 asc_board_t *boardp;
6037 int leftlen;
6038 int totlen;
6039 int len;
6040 int chip_scsi_id;
6041 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006043 boardp = ASC_BOARDP(shost);
6044 leftlen = cplen;
6045 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006047 len = asc_prt_line(cp, leftlen,
6048 "\nDevice Information for AdvanSys SCSI Host %d:\n",
6049 shost->host_no);
6050 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006052 if (ASC_NARROW_BOARD(boardp)) {
6053 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6054 } else {
6055 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006058 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6059 ASC_PRT_NEXT();
6060 for (i = 0; i <= ADV_MAX_TID; i++) {
6061 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6062 len = asc_prt_line(cp, leftlen, " %X,", i);
6063 ASC_PRT_NEXT();
6064 }
6065 }
6066 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6067 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006069 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070}
6071
6072/*
6073 * Display Wide Board BIOS Information.
6074 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006075static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006077 asc_board_t *boardp;
6078 int leftlen;
6079 int totlen;
6080 int len;
6081 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006083 boardp = ASC_BOARDP(shost);
6084 leftlen = cplen;
6085 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006087 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6088 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006090 /*
6091 * If the BIOS saved a valid signature, then fill in
6092 * the BIOS code segment base address.
6093 */
6094 if (boardp->bios_signature != 0x55AA) {
6095 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6096 ASC_PRT_NEXT();
6097 len = asc_prt_line(cp, leftlen,
6098 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6099 ASC_PRT_NEXT();
6100 len = asc_prt_line(cp, leftlen,
6101 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6102 ASC_PRT_NEXT();
6103 } else {
6104 major = (boardp->bios_version >> 12) & 0xF;
6105 minor = (boardp->bios_version >> 8) & 0xF;
6106 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006107
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006108 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6109 major, minor,
6110 letter >= 26 ? '?' : letter + 'A');
6111 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006113 /*
6114 * Current available ROM BIOS release is 3.1I for UW
6115 * and 3.2I for U2W. This code doesn't differentiate
6116 * UW and U2W boards.
6117 */
6118 if (major < 3 || (major <= 3 && minor < 1) ||
6119 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6120 len = asc_prt_line(cp, leftlen,
6121 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6122 ASC_PRT_NEXT();
6123 len = asc_prt_line(cp, leftlen,
6124 "ftp://ftp.connectcom.net/pub\n");
6125 ASC_PRT_NEXT();
6126 }
6127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006129 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130}
6131
6132/*
6133 * Add serial number to information bar if signature AAh
6134 * is found in at bit 15-9 (7 bits) of word 1.
6135 *
6136 * Serial Number consists fo 12 alpha-numeric digits.
6137 *
6138 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6139 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6140 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6141 * 5 - Product revision (A-J) Word0: " "
6142 *
6143 * Signature Word1: 15-9 (7 bits)
6144 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6145 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6146 *
6147 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6148 *
6149 * Note 1: Only production cards will have a serial number.
6150 *
6151 * Note 2: Signature is most significant 7 bits (0xFE).
6152 *
6153 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6154 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006155static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006157 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006159 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6160 return ASC_FALSE;
6161 } else {
6162 /*
6163 * First word - 6 digits.
6164 */
6165 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006167 /* Product type - 1st digit. */
6168 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6169 /* Product type is P=Prototype */
6170 *cp += 0x8;
6171 }
6172 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006174 /* Manufacturing location - 2nd digit. */
6175 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006177 /* Product ID - 3rd, 4th digits. */
6178 num = w & 0x3FF;
6179 *cp++ = '0' + (num / 100);
6180 num %= 100;
6181 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006183 /* Product revision - 5th digit. */
6184 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006186 /*
6187 * Second word
6188 */
6189 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006190
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006191 /*
6192 * Year - 6th digit.
6193 *
6194 * If bit 15 of third word is set, then the
6195 * last digit of the year is greater than 7.
6196 */
6197 if (serialnum[2] & 0x8000) {
6198 *cp++ = '8' + ((w & 0x1C0) >> 6);
6199 } else {
6200 *cp++ = '0' + ((w & 0x1C0) >> 6);
6201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006202
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006203 /* Week of year - 7th, 8th digits. */
6204 num = w & 0x003F;
6205 *cp++ = '0' + num / 10;
6206 num %= 10;
6207 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006209 /*
6210 * Third word
6211 */
6212 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006214 /* Serial number - 9th digit. */
6215 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006216
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006217 /* 10th, 11th, 12th digits. */
6218 num = w % 1000;
6219 *cp++ = '0' + num / 100;
6220 num %= 100;
6221 *cp++ = '0' + num / 10;
6222 num %= 10;
6223 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006225 *cp = '\0'; /* Null Terminate the string. */
6226 return ASC_TRUE;
6227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228}
6229
6230/*
6231 * asc_prt_asc_board_eeprom()
6232 *
6233 * Print board EEPROM configuration.
6234 *
6235 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6236 * cf. asc_prt_line().
6237 *
6238 * Return the number of characters copied into 'cp'. No more than
6239 * 'cplen' characters will be copied to 'cp'.
6240 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006241static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006243 asc_board_t *boardp;
6244 ASC_DVC_VAR *asc_dvc_varp;
6245 int leftlen;
6246 int totlen;
6247 int len;
6248 ASCEEP_CONFIG *ep;
6249 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006251 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006253 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006255 boardp = ASC_BOARDP(shost);
6256 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6257 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006259 leftlen = cplen;
6260 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006262 len = asc_prt_line(cp, leftlen,
6263 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6264 shost->host_no);
6265 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006267 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6268 == ASC_TRUE) {
6269 len =
6270 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6271 serialstr);
6272 ASC_PRT_NEXT();
6273 } else {
6274 if (ep->adapter_info[5] == 0xBB) {
6275 len = asc_prt_line(cp, leftlen,
6276 " Default Settings Used for EEPROM-less Adapter.\n");
6277 ASC_PRT_NEXT();
6278 } else {
6279 len = asc_prt_line(cp, leftlen,
6280 " Serial Number Signature Not Present.\n");
6281 ASC_PRT_NEXT();
6282 }
6283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006285 len = asc_prt_line(cp, leftlen,
6286 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6287 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6288 ep->max_tag_qng);
6289 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006291 len = asc_prt_line(cp, leftlen,
6292 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6293 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006295 len = asc_prt_line(cp, leftlen, " Target ID: ");
6296 ASC_PRT_NEXT();
6297 for (i = 0; i <= ASC_MAX_TID; i++) {
6298 len = asc_prt_line(cp, leftlen, " %d", i);
6299 ASC_PRT_NEXT();
6300 }
6301 len = asc_prt_line(cp, leftlen, "\n");
6302 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006304 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6305 ASC_PRT_NEXT();
6306 for (i = 0; i <= ASC_MAX_TID; i++) {
6307 len = asc_prt_line(cp, leftlen, " %c",
6308 (ep->
6309 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6310 'N');
6311 ASC_PRT_NEXT();
6312 }
6313 len = asc_prt_line(cp, leftlen, "\n");
6314 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006316 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6317 ASC_PRT_NEXT();
6318 for (i = 0; i <= ASC_MAX_TID; i++) {
6319 len = asc_prt_line(cp, leftlen, " %c",
6320 (ep->
6321 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6322 'N');
6323 ASC_PRT_NEXT();
6324 }
6325 len = asc_prt_line(cp, leftlen, "\n");
6326 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006327
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006328 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6329 ASC_PRT_NEXT();
6330 for (i = 0; i <= ASC_MAX_TID; i++) {
6331 len = asc_prt_line(cp, leftlen, " %c",
6332 (ep->
6333 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6334 'N');
6335 ASC_PRT_NEXT();
6336 }
6337 len = asc_prt_line(cp, leftlen, "\n");
6338 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006340 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6341 ASC_PRT_NEXT();
6342 for (i = 0; i <= ASC_MAX_TID; i++) {
6343 len = asc_prt_line(cp, leftlen, " %c",
6344 (ep->
6345 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6346 'N');
6347 ASC_PRT_NEXT();
6348 }
6349 len = asc_prt_line(cp, leftlen, "\n");
6350 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351
6352#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006353 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6354 len = asc_prt_line(cp, leftlen,
6355 " Host ISA DMA speed: %d MB/S\n",
6356 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6357 ASC_PRT_NEXT();
6358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359#endif /* CONFIG_ISA */
6360
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006361 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362}
6363
6364/*
6365 * asc_prt_adv_board_eeprom()
6366 *
6367 * Print board EEPROM configuration.
6368 *
6369 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6370 * cf. asc_prt_line().
6371 *
6372 * Return the number of characters copied into 'cp'. No more than
6373 * 'cplen' characters will be copied to 'cp'.
6374 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006375static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006376{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006377 asc_board_t *boardp;
6378 ADV_DVC_VAR *adv_dvc_varp;
6379 int leftlen;
6380 int totlen;
6381 int len;
6382 int i;
6383 char *termstr;
6384 uchar serialstr[13];
6385 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6386 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6387 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6388 ushort word;
6389 ushort *wordp;
6390 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006392 boardp = ASC_BOARDP(shost);
6393 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6394 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6395 ep_3550 = &boardp->eep_config.adv_3550_eep;
6396 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6397 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6398 } else {
6399 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006402 leftlen = cplen;
6403 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006405 len = asc_prt_line(cp, leftlen,
6406 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6407 shost->host_no);
6408 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006410 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6411 wordp = &ep_3550->serial_number_word1;
6412 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6413 wordp = &ep_38C0800->serial_number_word1;
6414 } else {
6415 wordp = &ep_38C1600->serial_number_word1;
6416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006417
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006418 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6419 len =
6420 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6421 serialstr);
6422 ASC_PRT_NEXT();
6423 } else {
6424 len = asc_prt_line(cp, leftlen,
6425 " Serial Number Signature Not Present.\n");
6426 ASC_PRT_NEXT();
6427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006429 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6430 len = asc_prt_line(cp, leftlen,
6431 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6432 ep_3550->adapter_scsi_id,
6433 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6434 ASC_PRT_NEXT();
6435 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6436 len = asc_prt_line(cp, leftlen,
6437 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6438 ep_38C0800->adapter_scsi_id,
6439 ep_38C0800->max_host_qng,
6440 ep_38C0800->max_dvc_qng);
6441 ASC_PRT_NEXT();
6442 } else {
6443 len = asc_prt_line(cp, leftlen,
6444 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6445 ep_38C1600->adapter_scsi_id,
6446 ep_38C1600->max_host_qng,
6447 ep_38C1600->max_dvc_qng);
6448 ASC_PRT_NEXT();
6449 }
6450 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6451 word = ep_3550->termination;
6452 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6453 word = ep_38C0800->termination_lvd;
6454 } else {
6455 word = ep_38C1600->termination_lvd;
6456 }
6457 switch (word) {
6458 case 1:
6459 termstr = "Low Off/High Off";
6460 break;
6461 case 2:
6462 termstr = "Low Off/High On";
6463 break;
6464 case 3:
6465 termstr = "Low On/High On";
6466 break;
6467 default:
6468 case 0:
6469 termstr = "Automatic";
6470 break;
6471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006472
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006473 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6474 len = asc_prt_line(cp, leftlen,
6475 " termination: %u (%s), bios_ctrl: 0x%x\n",
6476 ep_3550->termination, termstr,
6477 ep_3550->bios_ctrl);
6478 ASC_PRT_NEXT();
6479 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6480 len = asc_prt_line(cp, leftlen,
6481 " termination: %u (%s), bios_ctrl: 0x%x\n",
6482 ep_38C0800->termination_lvd, termstr,
6483 ep_38C0800->bios_ctrl);
6484 ASC_PRT_NEXT();
6485 } else {
6486 len = asc_prt_line(cp, leftlen,
6487 " termination: %u (%s), bios_ctrl: 0x%x\n",
6488 ep_38C1600->termination_lvd, termstr,
6489 ep_38C1600->bios_ctrl);
6490 ASC_PRT_NEXT();
6491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006492
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006493 len = asc_prt_line(cp, leftlen, " Target ID: ");
6494 ASC_PRT_NEXT();
6495 for (i = 0; i <= ADV_MAX_TID; i++) {
6496 len = asc_prt_line(cp, leftlen, " %X", i);
6497 ASC_PRT_NEXT();
6498 }
6499 len = asc_prt_line(cp, leftlen, "\n");
6500 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006501
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006502 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6503 word = ep_3550->disc_enable;
6504 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6505 word = ep_38C0800->disc_enable;
6506 } else {
6507 word = ep_38C1600->disc_enable;
6508 }
6509 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6510 ASC_PRT_NEXT();
6511 for (i = 0; i <= ADV_MAX_TID; i++) {
6512 len = asc_prt_line(cp, leftlen, " %c",
6513 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6514 ASC_PRT_NEXT();
6515 }
6516 len = asc_prt_line(cp, leftlen, "\n");
6517 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006518
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006519 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6520 word = ep_3550->tagqng_able;
6521 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6522 word = ep_38C0800->tagqng_able;
6523 } else {
6524 word = ep_38C1600->tagqng_able;
6525 }
6526 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6527 ASC_PRT_NEXT();
6528 for (i = 0; i <= ADV_MAX_TID; i++) {
6529 len = asc_prt_line(cp, leftlen, " %c",
6530 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6531 ASC_PRT_NEXT();
6532 }
6533 len = asc_prt_line(cp, leftlen, "\n");
6534 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006536 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6537 word = ep_3550->start_motor;
6538 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6539 word = ep_38C0800->start_motor;
6540 } else {
6541 word = ep_38C1600->start_motor;
6542 }
6543 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6544 ASC_PRT_NEXT();
6545 for (i = 0; i <= ADV_MAX_TID; i++) {
6546 len = asc_prt_line(cp, leftlen, " %c",
6547 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6548 ASC_PRT_NEXT();
6549 }
6550 len = asc_prt_line(cp, leftlen, "\n");
6551 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006552
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006553 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6554 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6555 ASC_PRT_NEXT();
6556 for (i = 0; i <= ADV_MAX_TID; i++) {
6557 len = asc_prt_line(cp, leftlen, " %c",
6558 (ep_3550->
6559 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6560 'Y' : 'N');
6561 ASC_PRT_NEXT();
6562 }
6563 len = asc_prt_line(cp, leftlen, "\n");
6564 ASC_PRT_NEXT();
6565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006566
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006567 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6568 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6569 ASC_PRT_NEXT();
6570 for (i = 0; i <= ADV_MAX_TID; i++) {
6571 len = asc_prt_line(cp, leftlen, " %c",
6572 (ep_3550->
6573 ultra_able & ADV_TID_TO_TIDMASK(i))
6574 ? 'Y' : 'N');
6575 ASC_PRT_NEXT();
6576 }
6577 len = asc_prt_line(cp, leftlen, "\n");
6578 ASC_PRT_NEXT();
6579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006580
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006581 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6582 word = ep_3550->wdtr_able;
6583 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6584 word = ep_38C0800->wdtr_able;
6585 } else {
6586 word = ep_38C1600->wdtr_able;
6587 }
6588 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6589 ASC_PRT_NEXT();
6590 for (i = 0; i <= ADV_MAX_TID; i++) {
6591 len = asc_prt_line(cp, leftlen, " %c",
6592 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6593 ASC_PRT_NEXT();
6594 }
6595 len = asc_prt_line(cp, leftlen, "\n");
6596 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006597
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006598 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6599 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6600 len = asc_prt_line(cp, leftlen,
6601 " Synchronous Transfer Speed (Mhz):\n ");
6602 ASC_PRT_NEXT();
6603 for (i = 0; i <= ADV_MAX_TID; i++) {
6604 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006605
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006606 if (i == 0) {
6607 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6608 } else if (i == 4) {
6609 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6610 } else if (i == 8) {
6611 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6612 } else if (i == 12) {
6613 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6614 }
6615 switch (sdtr_speed & ADV_MAX_TID) {
6616 case 0:
6617 speed_str = "Off";
6618 break;
6619 case 1:
6620 speed_str = " 5";
6621 break;
6622 case 2:
6623 speed_str = " 10";
6624 break;
6625 case 3:
6626 speed_str = " 20";
6627 break;
6628 case 4:
6629 speed_str = " 40";
6630 break;
6631 case 5:
6632 speed_str = " 80";
6633 break;
6634 default:
6635 speed_str = "Unk";
6636 break;
6637 }
6638 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6639 ASC_PRT_NEXT();
6640 if (i == 7) {
6641 len = asc_prt_line(cp, leftlen, "\n ");
6642 ASC_PRT_NEXT();
6643 }
6644 sdtr_speed >>= 4;
6645 }
6646 len = asc_prt_line(cp, leftlen, "\n");
6647 ASC_PRT_NEXT();
6648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006649
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006650 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006651}
6652
6653/*
6654 * asc_prt_driver_conf()
6655 *
6656 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6657 * cf. asc_prt_line().
6658 *
6659 * Return the number of characters copied into 'cp'. No more than
6660 * 'cplen' characters will be copied to 'cp'.
6661 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006662static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006663{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006664 asc_board_t *boardp;
6665 int leftlen;
6666 int totlen;
6667 int len;
6668 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006670 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006672 leftlen = cplen;
6673 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006675 len = asc_prt_line(cp, leftlen,
6676 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6677 shost->host_no);
6678 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006679
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006680 len = asc_prt_line(cp, leftlen,
6681 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6682 shost->host_busy, shost->last_reset, shost->max_id,
6683 shost->max_lun, shost->max_channel);
6684 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006685
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006686 len = asc_prt_line(cp, leftlen,
6687 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6688 shost->unique_id, shost->can_queue, shost->this_id,
6689 shost->sg_tablesize, shost->cmd_per_lun);
6690 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006691
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006692 len = asc_prt_line(cp, leftlen,
6693 " unchecked_isa_dma %d, use_clustering %d\n",
6694 shost->unchecked_isa_dma, shost->use_clustering);
6695 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006696
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006697 len = asc_prt_line(cp, leftlen,
6698 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6699 boardp->flags, boardp->last_reset, jiffies,
6700 boardp->asc_n_io_port);
6701 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006703 /* 'shost->n_io_port' may be truncated because it is only one byte. */
6704 len = asc_prt_line(cp, leftlen,
6705 " io_port 0x%x, n_io_port 0x%x\n",
6706 shost->io_port, shost->n_io_port);
6707 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006708
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006709 if (ASC_NARROW_BOARD(boardp)) {
6710 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6711 } else {
6712 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006714
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006715 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006716}
6717
6718/*
6719 * asc_prt_asc_board_info()
6720 *
6721 * Print dynamic board configuration information.
6722 *
6723 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6724 * cf. asc_prt_line().
6725 *
6726 * Return the number of characters copied into 'cp'. No more than
6727 * 'cplen' characters will be copied to 'cp'.
6728 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006729static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006730{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006731 asc_board_t *boardp;
6732 int chip_scsi_id;
6733 int leftlen;
6734 int totlen;
6735 int len;
6736 ASC_DVC_VAR *v;
6737 ASC_DVC_CFG *c;
6738 int i;
6739 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006740
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006741 boardp = ASC_BOARDP(shost);
6742 v = &boardp->dvc_var.asc_dvc_var;
6743 c = &boardp->dvc_cfg.asc_dvc_cfg;
6744 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006745
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006746 leftlen = cplen;
6747 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006748
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006749 len = asc_prt_line(cp, leftlen,
6750 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6751 shost->host_no);
6752 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006754 len = asc_prt_line(cp, leftlen,
6755 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6756 c->chip_version, c->lib_version, c->lib_serial_no,
6757 c->mcode_date);
6758 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006759
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006760 len = asc_prt_line(cp, leftlen,
6761 " mcode_version 0x%x, err_code %u\n",
6762 c->mcode_version, v->err_code);
6763 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006764
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006765 /* Current number of commands waiting for the host. */
6766 len = asc_prt_line(cp, leftlen,
6767 " Total Command Pending: %d\n", v->cur_total_qng);
6768 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006769
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006770 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6771 ASC_PRT_NEXT();
6772 for (i = 0; i <= ASC_MAX_TID; i++) {
6773 if ((chip_scsi_id == i) ||
6774 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6775 continue;
6776 }
6777 len = asc_prt_line(cp, leftlen, " %X:%c",
6778 i,
6779 (v->
6780 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6781 'Y' : 'N');
6782 ASC_PRT_NEXT();
6783 }
6784 len = asc_prt_line(cp, leftlen, "\n");
6785 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006787 /* Current number of commands waiting for a device. */
6788 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6789 ASC_PRT_NEXT();
6790 for (i = 0; i <= ASC_MAX_TID; i++) {
6791 if ((chip_scsi_id == i) ||
6792 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6793 continue;
6794 }
6795 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6796 ASC_PRT_NEXT();
6797 }
6798 len = asc_prt_line(cp, leftlen, "\n");
6799 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006801 /* Current limit on number of commands that can be sent to a device. */
6802 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6803 ASC_PRT_NEXT();
6804 for (i = 0; i <= ASC_MAX_TID; i++) {
6805 if ((chip_scsi_id == i) ||
6806 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6807 continue;
6808 }
6809 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
6810 ASC_PRT_NEXT();
6811 }
6812 len = asc_prt_line(cp, leftlen, "\n");
6813 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006814
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006815 /* Indicate whether the device has returned queue full status. */
6816 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
6817 ASC_PRT_NEXT();
6818 for (i = 0; i <= ASC_MAX_TID; i++) {
6819 if ((chip_scsi_id == i) ||
6820 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6821 continue;
6822 }
6823 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
6824 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
6825 i, boardp->queue_full_cnt[i]);
6826 } else {
6827 len = asc_prt_line(cp, leftlen, " %X:N", i);
6828 }
6829 ASC_PRT_NEXT();
6830 }
6831 len = asc_prt_line(cp, leftlen, "\n");
6832 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006834 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6835 ASC_PRT_NEXT();
6836 for (i = 0; i <= ASC_MAX_TID; i++) {
6837 if ((chip_scsi_id == i) ||
6838 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6839 continue;
6840 }
6841 len = asc_prt_line(cp, leftlen, " %X:%c",
6842 i,
6843 (v->
6844 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6845 'N');
6846 ASC_PRT_NEXT();
6847 }
6848 len = asc_prt_line(cp, leftlen, "\n");
6849 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006851 for (i = 0; i <= ASC_MAX_TID; i++) {
6852 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006854 if ((chip_scsi_id == i) ||
6855 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6856 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
6857 continue;
6858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006859
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006860 len = asc_prt_line(cp, leftlen, " %X:", i);
6861 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006862
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006863 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
6864 len = asc_prt_line(cp, leftlen, " Asynchronous");
6865 ASC_PRT_NEXT();
6866 } else {
6867 syn_period_ix =
6868 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
6869 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006870
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006871 len = asc_prt_line(cp, leftlen,
6872 " Transfer Period Factor: %d (%d.%d Mhz),",
6873 v->sdtr_period_tbl[syn_period_ix],
6874 250 /
6875 v->sdtr_period_tbl[syn_period_ix],
6876 ASC_TENTHS(250,
6877 v->
6878 sdtr_period_tbl
6879 [syn_period_ix]));
6880 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006881
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006882 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6883 boardp->
6884 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
6885 ASC_PRT_NEXT();
6886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006887
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006888 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6889 len = asc_prt_line(cp, leftlen, "*\n");
6890 renegotiate = 1;
6891 } else {
6892 len = asc_prt_line(cp, leftlen, "\n");
6893 }
6894 ASC_PRT_NEXT();
6895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006896
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006897 if (renegotiate) {
6898 len = asc_prt_line(cp, leftlen,
6899 " * = Re-negotiation pending before next command.\n");
6900 ASC_PRT_NEXT();
6901 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006902
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006903 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006904}
6905
6906/*
6907 * asc_prt_adv_board_info()
6908 *
6909 * Print dynamic board configuration information.
6910 *
6911 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6912 * cf. asc_prt_line().
6913 *
6914 * Return the number of characters copied into 'cp'. No more than
6915 * 'cplen' characters will be copied to 'cp'.
6916 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006917static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006918{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006919 asc_board_t *boardp;
6920 int leftlen;
6921 int totlen;
6922 int len;
6923 int i;
6924 ADV_DVC_VAR *v;
6925 ADV_DVC_CFG *c;
6926 AdvPortAddr iop_base;
6927 ushort chip_scsi_id;
6928 ushort lramword;
6929 uchar lrambyte;
6930 ushort tagqng_able;
6931 ushort sdtr_able, wdtr_able;
6932 ushort wdtr_done, sdtr_done;
6933 ushort period = 0;
6934 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006936 boardp = ASC_BOARDP(shost);
6937 v = &boardp->dvc_var.adv_dvc_var;
6938 c = &boardp->dvc_cfg.adv_dvc_cfg;
6939 iop_base = v->iop_base;
6940 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006941
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006942 leftlen = cplen;
6943 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006944
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006945 len = asc_prt_line(cp, leftlen,
6946 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6947 shost->host_no);
6948 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006949
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006950 len = asc_prt_line(cp, leftlen,
6951 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
6952 v->iop_base,
6953 AdvReadWordRegister(iop_base,
6954 IOPW_SCSI_CFG1) & CABLE_DETECT,
6955 v->err_code);
6956 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006957
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006958 len = asc_prt_line(cp, leftlen,
6959 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
6960 c->chip_version, c->lib_version, c->mcode_date,
6961 c->mcode_version);
6962 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006963
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006964 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
6965 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
6966 ASC_PRT_NEXT();
6967 for (i = 0; i <= ADV_MAX_TID; i++) {
6968 if ((chip_scsi_id == i) ||
6969 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6970 continue;
6971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006972
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006973 len = asc_prt_line(cp, leftlen, " %X:%c",
6974 i,
6975 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6976 'N');
6977 ASC_PRT_NEXT();
6978 }
6979 len = asc_prt_line(cp, leftlen, "\n");
6980 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006981
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006982 len = asc_prt_line(cp, leftlen, " Queue Limit:");
6983 ASC_PRT_NEXT();
6984 for (i = 0; i <= ADV_MAX_TID; i++) {
6985 if ((chip_scsi_id == i) ||
6986 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6987 continue;
6988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006989
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006990 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
6991 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006992
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006993 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6994 ASC_PRT_NEXT();
6995 }
6996 len = asc_prt_line(cp, leftlen, "\n");
6997 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006998
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006999 len = asc_prt_line(cp, leftlen, " Command Pending:");
7000 ASC_PRT_NEXT();
7001 for (i = 0; i <= ADV_MAX_TID; i++) {
7002 if ((chip_scsi_id == i) ||
7003 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7004 continue;
7005 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007006
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007007 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
7008 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007009
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007010 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
7011 ASC_PRT_NEXT();
7012 }
7013 len = asc_prt_line(cp, leftlen, "\n");
7014 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007015
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007016 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
7017 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
7018 ASC_PRT_NEXT();
7019 for (i = 0; i <= ADV_MAX_TID; i++) {
7020 if ((chip_scsi_id == i) ||
7021 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7022 continue;
7023 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007024
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007025 len = asc_prt_line(cp, leftlen, " %X:%c",
7026 i,
7027 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7028 'N');
7029 ASC_PRT_NEXT();
7030 }
7031 len = asc_prt_line(cp, leftlen, "\n");
7032 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007033
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007034 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
7035 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
7036 ASC_PRT_NEXT();
7037 for (i = 0; i <= ADV_MAX_TID; i++) {
7038 if ((chip_scsi_id == i) ||
7039 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7040 continue;
7041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007043 AdvReadWordLram(iop_base,
7044 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7045 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007046
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007047 len = asc_prt_line(cp, leftlen, " %X:%d",
7048 i, (lramword & 0x8000) ? 16 : 8);
7049 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007050
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007051 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
7052 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7053 len = asc_prt_line(cp, leftlen, "*");
7054 ASC_PRT_NEXT();
7055 renegotiate = 1;
7056 }
7057 }
7058 len = asc_prt_line(cp, leftlen, "\n");
7059 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007060
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007061 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7062 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7063 ASC_PRT_NEXT();
7064 for (i = 0; i <= ADV_MAX_TID; i++) {
7065 if ((chip_scsi_id == i) ||
7066 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7067 continue;
7068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007069
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007070 len = asc_prt_line(cp, leftlen, " %X:%c",
7071 i,
7072 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7073 'N');
7074 ASC_PRT_NEXT();
7075 }
7076 len = asc_prt_line(cp, leftlen, "\n");
7077 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007078
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007079 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7080 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007082 AdvReadWordLram(iop_base,
7083 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7084 lramword);
7085 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007086
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007087 if ((chip_scsi_id == i) ||
7088 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7089 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7090 continue;
7091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007092
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007093 len = asc_prt_line(cp, leftlen, " %X:", i);
7094 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007096 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7097 len = asc_prt_line(cp, leftlen, " Asynchronous");
7098 ASC_PRT_NEXT();
7099 } else {
7100 len =
7101 asc_prt_line(cp, leftlen,
7102 " Transfer Period Factor: ");
7103 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007105 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7106 len =
7107 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7108 ASC_PRT_NEXT();
7109 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7110 len =
7111 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7112 ASC_PRT_NEXT();
7113 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007114
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007115 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007117 if (period == 0) { /* Should never happen. */
7118 len =
7119 asc_prt_line(cp, leftlen,
7120 "%d (? Mhz), ");
7121 ASC_PRT_NEXT();
7122 } else {
7123 len = asc_prt_line(cp, leftlen,
7124 "%d (%d.%d Mhz),",
7125 period, 250 / period,
7126 ASC_TENTHS(250,
7127 period));
7128 ASC_PRT_NEXT();
7129 }
7130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007131
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007132 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7133 lramword & 0x1F);
7134 ASC_PRT_NEXT();
7135 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007136
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007137 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7138 len = asc_prt_line(cp, leftlen, "*\n");
7139 renegotiate = 1;
7140 } else {
7141 len = asc_prt_line(cp, leftlen, "\n");
7142 }
7143 ASC_PRT_NEXT();
7144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007145
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007146 if (renegotiate) {
7147 len = asc_prt_line(cp, leftlen,
7148 " * = Re-negotiation pending before next command.\n");
7149 ASC_PRT_NEXT();
7150 }
7151
7152 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153}
7154
7155/*
7156 * asc_proc_copy()
7157 *
7158 * Copy proc information to a read buffer taking into account the current
7159 * read offset in the file and the remaining space in the read buffer.
7160 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007161static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007162asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007163 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007164{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007165 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007167 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7168 (unsigned)offset, (unsigned)advoffset, cplen);
7169 if (offset <= advoffset) {
7170 /* Read offset below current offset, copy everything. */
7171 cnt = min(cplen, leftlen);
7172 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7173 (ulong)curbuf, (ulong)cp, cnt);
7174 memcpy(curbuf, cp, cnt);
7175 } else if (offset < advoffset + cplen) {
7176 /* Read offset within current range, partial copy. */
7177 cnt = (advoffset + cplen) - offset;
7178 cp = (cp + cplen) - cnt;
7179 cnt = min(cnt, leftlen);
7180 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7181 (ulong)curbuf, (ulong)cp, cnt);
7182 memcpy(curbuf, cp, cnt);
7183 }
7184 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007185}
7186
7187/*
7188 * asc_prt_line()
7189 *
7190 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7191 *
7192 * Return 0 if printing to the console, otherwise return the number of
7193 * bytes written to the buffer.
7194 *
7195 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7196 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7197 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007198static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007199{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007200 va_list args;
7201 int ret;
7202 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007203
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007204 va_start(args, fmt);
7205 ret = vsprintf(s, fmt, args);
7206 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7207 if (buf == NULL) {
7208 (void)printk(s);
7209 ret = 0;
7210 } else {
7211 ret = min(buflen, ret);
7212 memcpy(buf, s, ret);
7213 }
7214 va_end(args);
7215 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007216}
7217#endif /* CONFIG_PROC_FS */
7218
Linus Torvalds1da177e2005-04-16 15:20:36 -07007219/*
7220 * --- Functions Required by the Asc Library
7221 */
7222
7223/*
7224 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7225 * global variable which is incremented once every 5 ms
7226 * from a timer interrupt, because this function may be
7227 * called when interrupts are disabled.
7228 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007229static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007230{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007231 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7232 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007233}
7234
7235/*
7236 * Currently and inline noop but leave as a placeholder.
7237 * Leave DvcEnterCritical() as a noop placeholder.
7238 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007239static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007240{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007241 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007242}
7243
7244/*
7245 * Critical sections are all protected by the board spinlock.
7246 * Leave DvcLeaveCritical() as a noop placeholder.
7247 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007248static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007249{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007250 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007251}
7252
7253/*
7254 * void
7255 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7256 *
7257 * Calling/Exit State:
7258 * none
7259 *
7260 * Description:
7261 * Output an ASC_SCSI_Q structure to the chip
7262 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007263static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007264DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7265{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007266 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007267
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007268 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7269 AscSetChipLramAddr(iop_base, s_addr);
7270 for (i = 0; i < 2 * words; i += 2) {
7271 if (i == 4 || i == 20) {
7272 continue;
7273 }
7274 outpw(iop_base + IOP_RAM_DATA,
7275 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007277}
7278
7279/*
7280 * void
7281 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7282 *
7283 * Calling/Exit State:
7284 * none
7285 *
7286 * Description:
7287 * Input an ASC_QDONE_INFO structure from the chip
7288 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007289static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7291{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007292 int i;
7293 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007295 AscSetChipLramAddr(iop_base, s_addr);
7296 for (i = 0; i < 2 * words; i += 2) {
7297 if (i == 10) {
7298 continue;
7299 }
7300 word = inpw(iop_base + IOP_RAM_DATA);
7301 inbuf[i] = word & 0xff;
7302 inbuf[i + 1] = (word >> 8) & 0xff;
7303 }
7304 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007305}
7306
7307/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007308 * Return the BIOS address of the adapter at the specified
7309 * I/O port and with the specified bus type.
7310 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007311static unsigned short __devinit
7312AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007313{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007314 unsigned short cfg_lsw;
7315 unsigned short bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007316
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007317 /*
7318 * The PCI BIOS is re-located by the motherboard BIOS. Because
7319 * of this the driver can not determine where a PCI BIOS is
7320 * loaded and executes.
7321 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007322 if (bus_type & ASC_IS_PCI)
7323 return 0;
7324
Linus Torvalds1da177e2005-04-16 15:20:36 -07007325#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007326 if ((bus_type & ASC_IS_EISA) != 0) {
7327 cfg_lsw = AscGetEisaChipCfg(iop_base);
7328 cfg_lsw &= 0x000F;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007329 bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
7330 return bios_addr;
7331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007332#endif /* CONFIG_ISA */
7333
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007334 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007335
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007336 /*
7337 * ISA PnP uses the top bit as the 32K BIOS flag
7338 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007339 if (bus_type == ASC_IS_ISAPNP)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007340 cfg_lsw &= 0x7FFF;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007341 bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
7342 return bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007343}
7344
Linus Torvalds1da177e2005-04-16 15:20:36 -07007345/*
7346 * --- Functions Required by the Adv Library
7347 */
7348
7349/*
7350 * DvcGetPhyAddr()
7351 *
7352 * Return the physical address of 'vaddr' and set '*lenp' to the
7353 * number of physically contiguous bytes that follow 'vaddr'.
7354 * 'flag' indicates the type of structure whose physical address
7355 * is being translated.
7356 *
7357 * Note: Because Linux currently doesn't page the kernel and all
7358 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7359 */
7360ADV_PADDR
7361DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007362 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007363{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007364 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007365
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007366 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007367
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007368 ASC_DBG4(4,
7369 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7370 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7371 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007372
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007373 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007374}
7375
7376/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007377 * --- Tracing and Debugging Functions
7378 */
7379
7380#ifdef ADVANSYS_STATS
7381#ifdef CONFIG_PROC_FS
7382/*
7383 * asc_prt_board_stats()
7384 *
7385 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7386 * cf. asc_prt_line().
7387 *
7388 * Return the number of characters copied into 'cp'. No more than
7389 * 'cplen' characters will be copied to 'cp'.
7390 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007391static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007392{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007393 int leftlen;
7394 int totlen;
7395 int len;
7396 struct asc_stats *s;
7397 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007398
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007399 leftlen = cplen;
7400 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007401
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007402 boardp = ASC_BOARDP(shost);
7403 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007404
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007405 len = asc_prt_line(cp, leftlen,
7406 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7407 shost->host_no);
7408 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007410 len = asc_prt_line(cp, leftlen,
7411 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7412 s->queuecommand, s->reset, s->biosparam,
7413 s->interrupt);
7414 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007415
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007416 len = asc_prt_line(cp, leftlen,
7417 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7418 s->callback, s->done, s->build_error,
7419 s->adv_build_noreq, s->adv_build_nosg);
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,
7423 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7424 s->exe_noerror, s->exe_busy, s->exe_error,
7425 s->exe_unknown);
7426 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007428 /*
7429 * Display data transfer statistics.
7430 */
7431 if (s->cont_cnt > 0) {
7432 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7433 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007434
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007435 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7436 s->cont_xfer / 2,
7437 ASC_TENTHS(s->cont_xfer, 2));
7438 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007439
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007440 /* Contiguous transfer average size */
7441 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7442 (s->cont_xfer / 2) / s->cont_cnt,
7443 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7444 ASC_PRT_NEXT();
7445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007446
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007447 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007448
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007449 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7450 s->sg_cnt, s->sg_elem);
7451 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007452
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007453 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7454 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7455 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007457 /* Scatter gather transfer statistics */
7458 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7459 s->sg_elem / s->sg_cnt,
7460 ASC_TENTHS(s->sg_elem, s->sg_cnt));
7461 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007462
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007463 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
7464 (s->sg_xfer / 2) / s->sg_elem,
7465 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7466 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007467
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007468 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7469 (s->sg_xfer / 2) / s->sg_cnt,
7470 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7471 ASC_PRT_NEXT();
7472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007473
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007474 /*
7475 * Display request queuing statistics.
7476 */
7477 len = asc_prt_line(cp, leftlen,
7478 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7479 HZ);
7480 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007481
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007482 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007483}
7484
7485/*
7486 * asc_prt_target_stats()
7487 *
7488 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7489 * cf. asc_prt_line().
7490 *
7491 * This is separated from asc_prt_board_stats because a full set
7492 * of targets will overflow ASC_PRTBUF_SIZE.
7493 *
7494 * Return the number of characters copied into 'cp'. No more than
7495 * 'cplen' characters will be copied to 'cp'.
7496 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007497static int
7498asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007499{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007500 int leftlen;
7501 int totlen;
7502 int len;
7503 struct asc_stats *s;
7504 ushort chip_scsi_id;
7505 asc_board_t *boardp;
7506 asc_queue_t *active;
7507 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007508
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007509 leftlen = cplen;
7510 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007511
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007512 boardp = ASC_BOARDP(shost);
7513 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007514
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007515 active = &ASC_BOARDP(shost)->active;
7516 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007517
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007518 if (ASC_NARROW_BOARD(boardp)) {
7519 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7520 } else {
7521 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007523
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007524 if ((chip_scsi_id == tgt_id) ||
7525 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7526 return 0;
7527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007528
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007529 do {
7530 if (active->q_tot_cnt[tgt_id] > 0
7531 || waiting->q_tot_cnt[tgt_id] > 0) {
7532 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
7533 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007534
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007535 len = asc_prt_line(cp, leftlen,
7536 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7537 active->q_cur_cnt[tgt_id],
7538 active->q_max_cnt[tgt_id],
7539 active->q_tot_cnt[tgt_id],
7540 active->q_min_tim[tgt_id],
7541 active->q_max_tim[tgt_id],
7542 (active->q_tot_cnt[tgt_id] ==
7543 0) ? 0 : (active->
7544 q_tot_tim[tgt_id] /
7545 active->
7546 q_tot_cnt[tgt_id]),
7547 (active->q_tot_cnt[tgt_id] ==
7548 0) ? 0 : ASC_TENTHS(active->
7549 q_tot_tim
7550 [tgt_id],
7551 active->
7552 q_tot_cnt
7553 [tgt_id]));
7554 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007555
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007556 len = asc_prt_line(cp, leftlen,
7557 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7558 waiting->q_cur_cnt[tgt_id],
7559 waiting->q_max_cnt[tgt_id],
7560 waiting->q_tot_cnt[tgt_id],
7561 waiting->q_min_tim[tgt_id],
7562 waiting->q_max_tim[tgt_id],
7563 (waiting->q_tot_cnt[tgt_id] ==
7564 0) ? 0 : (waiting->
7565 q_tot_tim[tgt_id] /
7566 waiting->
7567 q_tot_cnt[tgt_id]),
7568 (waiting->q_tot_cnt[tgt_id] ==
7569 0) ? 0 : ASC_TENTHS(waiting->
7570 q_tot_tim
7571 [tgt_id],
7572 waiting->
7573 q_tot_cnt
7574 [tgt_id]));
7575 ASC_PRT_NEXT();
7576 }
7577 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007578
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007579 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007580}
7581#endif /* CONFIG_PROC_FS */
7582#endif /* ADVANSYS_STATS */
7583
7584#ifdef ADVANSYS_DEBUG
7585/*
7586 * asc_prt_scsi_host()
7587 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007588static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007589{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007590 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007592 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007593
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007594 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7595 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7596 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007597
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007598 printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
7599 (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007600
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007601 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7602 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007603
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007604 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7605 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007606
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007607 if (ASC_NARROW_BOARD(boardp)) {
7608 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7609 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7610 } else {
7611 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7612 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007614}
7615
7616/*
7617 * asc_prt_scsi_cmnd()
7618 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007619static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007620{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007621 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007622
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007623 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7624 (ulong)s->device->host, (ulong)s->device, s->device->id,
7625 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007627 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007628
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007629 printk("sc_data_direction %u, resid %d\n",
7630 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007631
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007632 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007633
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007634 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7635 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007636
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007637 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007638
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007639 printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
7640 s->scsi_done, s->done, s->host_scribble, s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007641
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007642 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007643}
7644
7645/*
7646 * asc_prt_asc_dvc_var()
7647 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007648static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007649{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007650 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007651
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007652 printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
7653 "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007654
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007655 printk(" bus_type %d, isr_callback 0x%p, exe_callback 0x%p, "
7656 "init_sdtr 0x%x,\n", h->bus_type, h->isr_callback,
7657 h->exe_callback, (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007658
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007659 printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
7660 "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
7661 (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
7662 (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007663
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007664 printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
7665 "%u,\n", (unsigned)h->queue_full_or_busy,
7666 (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007667
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007668 printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
7669 "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
7670 (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
7671 (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007672
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007673 printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
7674 "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
7675 (unsigned)h->init_state, (unsigned)h->no_scam,
7676 (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007677
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007678 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007679}
7680
7681/*
7682 * asc_prt_asc_dvc_cfg()
7683 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007684static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007685{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007686 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007687
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007688 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7689 h->can_tagged_qng, h->cmd_qng_enabled);
7690 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7691 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007693 printk
7694 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7695 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7696 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007698 printk
7699 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7700 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7701 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007702
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007703 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7704 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007705}
7706
7707/*
7708 * asc_prt_asc_scsi_q()
7709 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007710static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007711{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007712 ASC_SG_HEAD *sgp;
7713 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007714
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007715 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007716
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007717 printk
7718 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7719 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7720 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007721
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007722 printk
7723 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7724 (ulong)le32_to_cpu(q->q1.data_addr),
7725 (ulong)le32_to_cpu(q->q1.data_cnt),
7726 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007727
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007728 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
7729 (ulong)q->cdbptr, q->q2.cdb_len,
7730 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007731
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007732 if (q->sg_head) {
7733 sgp = q->sg_head;
7734 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
7735 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
7736 sgp->queue_cnt);
7737 for (i = 0; i < sgp->entry_cnt; i++) {
7738 printk(" [%u]: addr 0x%lx, bytes %lu\n",
7739 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
7740 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
7741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007744}
7745
7746/*
7747 * asc_prt_asc_qdone_info()
7748 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007749static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007750{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007751 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
7752 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
7753 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
7754 q->d2.tag_code);
7755 printk
7756 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
7757 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007758}
7759
7760/*
7761 * asc_prt_adv_dvc_var()
7762 *
7763 * Display an ADV_DVC_VAR structure.
7764 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007765static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007766{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007767 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007769 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
7770 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007771
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007772 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
7773 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
7774 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007776 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
7777 (unsigned)h->start_motor,
7778 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007779
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007780 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
7781 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
7782 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007783
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007784 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
7785 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007787 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
7788 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007790 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
7791 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007792}
7793
7794/*
7795 * asc_prt_adv_dvc_cfg()
7796 *
7797 * Display an ADV_DVC_CFG structure.
7798 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007799static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007800{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007801 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007803 printk(" disc_enable 0x%x, termination 0x%x\n",
7804 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007805
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007806 printk(" chip_version 0x%x, mcode_date 0x%x\n",
7807 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007808
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007809 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
7810 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007811
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007812 printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
7813 h->control_flag, h->pci_slot_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007814}
7815
7816/*
7817 * asc_prt_adv_scsi_req_q()
7818 *
7819 * Display an ADV_SCSI_REQ_Q structure.
7820 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007821static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007822{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007823 int sg_blk_cnt;
7824 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007825
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007826 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007827
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007828 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
7829 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007830
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007831 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
7832 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007834 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7835 (ulong)le32_to_cpu(q->data_cnt),
7836 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007837
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007838 printk
7839 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
7840 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007841
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007842 printk(" sg_working_ix 0x%x, target_cmd %u\n",
7843 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007844
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007845 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
7846 (ulong)le32_to_cpu(q->scsiq_rptr),
7847 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007848
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007849 /* Display the request's ADV_SG_BLOCK structures. */
7850 if (q->sg_list_ptr != NULL) {
7851 sg_blk_cnt = 0;
7852 while (1) {
7853 /*
7854 * 'sg_ptr' is a physical address. Convert it to a virtual
7855 * address by indexing 'sg_blk_cnt' into the virtual address
7856 * array 'sg_list_ptr'.
7857 *
7858 * XXX - Assumes all SG physical blocks are virtually contiguous.
7859 */
7860 sg_ptr =
7861 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
7862 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
7863 if (sg_ptr->sg_ptr == 0) {
7864 break;
7865 }
7866 sg_blk_cnt++;
7867 }
7868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007869}
7870
7871/*
7872 * asc_prt_adv_sgblock()
7873 *
7874 * Display an ADV_SG_BLOCK structure.
7875 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007876static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007877{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007878 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007880 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
7881 (ulong)b, sgblockno);
7882 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
7883 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
7884 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
7885 if (b->sg_ptr != 0) {
7886 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
7887 }
7888 for (i = 0; i < b->sg_cnt; i++) {
7889 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
7890 i, (ulong)b->sg_list[i].sg_addr,
7891 (ulong)b->sg_list[i].sg_count);
7892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007893}
7894
7895/*
7896 * asc_prt_hex()
7897 *
7898 * Print hexadecimal output in 4 byte groupings 32 bytes
7899 * or 8 double-words per line.
7900 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007901static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007902{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007903 int i;
7904 int j;
7905 int k;
7906 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007908 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007909
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007910 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007911
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007912 /* Display a maximum of 8 double-words per line. */
7913 if ((k = (l - i) / 4) >= 8) {
7914 k = 8;
7915 m = 0;
7916 } else {
7917 m = (l - i) % 4;
7918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007920 for (j = 0; j < k; j++) {
7921 printk(" %2.2X%2.2X%2.2X%2.2X",
7922 (unsigned)s[i + (j * 4)],
7923 (unsigned)s[i + (j * 4) + 1],
7924 (unsigned)s[i + (j * 4) + 2],
7925 (unsigned)s[i + (j * 4) + 3]);
7926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007927
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007928 switch (m) {
7929 case 0:
7930 default:
7931 break;
7932 case 1:
7933 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
7934 break;
7935 case 2:
7936 printk(" %2.2X%2.2X",
7937 (unsigned)s[i + (j * 4)],
7938 (unsigned)s[i + (j * 4) + 1]);
7939 break;
7940 case 3:
7941 printk(" %2.2X%2.2X%2.2X",
7942 (unsigned)s[i + (j * 4) + 1],
7943 (unsigned)s[i + (j * 4) + 2],
7944 (unsigned)s[i + (j * 4) + 3]);
7945 break;
7946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007948 printk("\n");
7949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007950}
7951#endif /* ADVANSYS_DEBUG */
7952
7953/*
7954 * --- Asc Library Functions
7955 */
7956
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007957static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007958{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007959 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007960
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007961 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7962 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
7963 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007964}
7965
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007966static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007967{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007968 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007969
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007970 if (AscGetChipScsiID(iop_base) == new_host_id) {
7971 return (new_host_id);
7972 }
7973 cfg_lsw = AscGetChipCfgLsw(iop_base);
7974 cfg_lsw &= 0xF8FF;
7975 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
7976 AscSetChipCfgLsw(iop_base, cfg_lsw);
7977 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007978}
7979
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007980static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007981{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007982 unsigned char sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007984 AscSetBank(iop_base, 1);
7985 sc = inp(iop_base + IOP_REG_SC);
7986 AscSetBank(iop_base, 0);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007987 return sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007988}
7989
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007990static unsigned char __devinit
7991AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007992{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007993 if (bus_type & ASC_IS_EISA) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007994 PortAddr eisa_iop;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007995 unsigned char revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007996 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7997 (PortAddr) ASC_EISA_REV_IOP_MASK;
7998 revision = inp(eisa_iop);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007999 return ASC_CHIP_MIN_VER_EISA - 1 + revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008000 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -06008001 return AscGetChipVerNo(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008002}
8003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008004static ASC_DCNT
8005AscLoadMicroCode(PortAddr iop_base,
8006 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008007{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008008 ASC_DCNT chksum;
8009 ushort mcode_word_size;
8010 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008011
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008012 /* Write the microcode buffer starting at LRAM address 0. */
8013 mcode_word_size = (ushort)(mcode_size >> 1);
8014 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
8015 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008016
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008017 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
8018 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
8019 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
8020 (ushort)ASC_CODE_SEC_BEG,
8021 (ushort)((mcode_size -
8022 s_addr - (ushort)
8023 ASC_CODE_SEC_BEG) /
8024 2));
8025 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
8026 (ulong)mcode_chksum);
8027 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
8028 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
8029 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008030}
8031
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008032static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008033{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008034 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008035
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008036 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
8037 iop_base, AscGetChipSignatureByte(iop_base));
8038 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
8039 ASC_DBG2(1,
8040 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
8041 iop_base, AscGetChipSignatureWord(iop_base));
8042 sig_word = AscGetChipSignatureWord(iop_base);
8043 if ((sig_word == (ushort)ASC_1000_ID0W) ||
8044 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
8045 return (1);
8046 }
8047 }
8048 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008049}
8050
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008051static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008052{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008053 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
8054 AscSetChipStatus(iop_base, 0);
8055 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008056}
8057
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008058static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008059{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008060 ushort cfg_lsw;
8061 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008062
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008063 if ((bus_type & ASC_IS_EISA) != 0) {
8064 cfg_lsw = AscGetEisaChipCfg(iop_base);
8065 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8066 if ((chip_irq == 13) || (chip_irq > 15)) {
8067 return (0);
8068 }
8069 return (chip_irq);
8070 }
8071 if ((bus_type & ASC_IS_VL) != 0) {
8072 cfg_lsw = AscGetChipCfgLsw(iop_base);
8073 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8074 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8075 return (0);
8076 }
8077 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8078 }
8079 cfg_lsw = AscGetChipCfgLsw(iop_base);
8080 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8081 if (chip_irq == 3)
8082 chip_irq += (uchar)2;
8083 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008084}
8085
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008086static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008087AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008088{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008089 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008090
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008091 if ((bus_type & ASC_IS_VL) != 0) {
8092 if (irq_no != 0) {
8093 if ((irq_no < ASC_MIN_IRQ_NO)
8094 || (irq_no > ASC_MAX_IRQ_NO)) {
8095 irq_no = 0;
8096 } else {
8097 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8098 }
8099 }
8100 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8101 cfg_lsw |= (ushort)0x0010;
8102 AscSetChipCfgLsw(iop_base, cfg_lsw);
8103 AscToggleIRQAct(iop_base);
8104 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8105 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8106 AscSetChipCfgLsw(iop_base, cfg_lsw);
8107 AscToggleIRQAct(iop_base);
8108 return (AscGetChipIRQ(iop_base, bus_type));
8109 }
8110 if ((bus_type & (ASC_IS_ISA)) != 0) {
8111 if (irq_no == 15)
8112 irq_no -= (uchar)2;
8113 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8114 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8115 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8116 AscSetChipCfgLsw(iop_base, cfg_lsw);
8117 return (AscGetChipIRQ(iop_base, bus_type));
8118 }
8119 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008120}
8121
8122#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008123static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008124{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008125 if (dma_channel < 4) {
8126 outp(0x000B, (ushort)(0xC0 | dma_channel));
8127 outp(0x000A, dma_channel);
8128 } else if (dma_channel < 8) {
8129 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8130 outp(0x00D4, (ushort)(dma_channel - 4));
8131 }
8132 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008133}
8134#endif /* CONFIG_ISA */
8135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008136static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008137{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008138 EXT_MSG ext_msg;
8139 EXT_MSG out_msg;
8140 ushort halt_q_addr;
8141 int sdtr_accept;
8142 ushort int_halt_code;
8143 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8144 ASC_SCSI_BIT_ID_TYPE target_id;
8145 PortAddr iop_base;
8146 uchar tag_code;
8147 uchar q_status;
8148 uchar halt_qp;
8149 uchar sdtr_data;
8150 uchar target_ix;
8151 uchar q_cntl, tid_no;
8152 uchar cur_dvc_qng;
8153 uchar asyn_sdtr;
8154 uchar scsi_status;
8155 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008157 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8158 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008159
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008160 iop_base = asc_dvc->iop_base;
8161 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008162
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008163 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8164 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8165 target_ix = AscReadLramByte(iop_base,
8166 (ushort)(halt_q_addr +
8167 (ushort)ASC_SCSIQ_B_TARGET_IX));
8168 q_cntl =
8169 AscReadLramByte(iop_base,
8170 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8171 tid_no = ASC_TIX_TO_TID(target_ix);
8172 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8173 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8174 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8175 } else {
8176 asyn_sdtr = 0;
8177 }
8178 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8179 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8180 AscSetChipSDTR(iop_base, 0, tid_no);
8181 boardp->sdtr_data[tid_no] = 0;
8182 }
8183 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8184 return (0);
8185 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8186 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8187 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8188 boardp->sdtr_data[tid_no] = asyn_sdtr;
8189 }
8190 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8191 return (0);
8192 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008193
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008194 AscMemWordCopyPtrFromLram(iop_base,
8195 ASCV_MSGIN_BEG,
8196 (uchar *)&ext_msg,
8197 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008198
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008199 if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8200 ext_msg.msg_req == EXTENDED_SDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008201 ext_msg.msg_len == MS_SDTR_LEN) {
8202 sdtr_accept = TRUE;
8203 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008204
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008205 sdtr_accept = FALSE;
8206 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8207 }
8208 if ((ext_msg.xfer_period <
8209 asc_dvc->sdtr_period_tbl[asc_dvc->
8210 host_init_sdtr_index])
8211 || (ext_msg.xfer_period >
8212 asc_dvc->sdtr_period_tbl[asc_dvc->
8213 max_sdtr_index])) {
8214 sdtr_accept = FALSE;
8215 ext_msg.xfer_period =
8216 asc_dvc->sdtr_period_tbl[asc_dvc->
8217 host_init_sdtr_index];
8218 }
8219 if (sdtr_accept) {
8220 sdtr_data =
8221 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8222 ext_msg.req_ack_offset);
8223 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008224
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008225 q_cntl |= QC_MSG_OUT;
8226 asc_dvc->init_sdtr &= ~target_id;
8227 asc_dvc->sdtr_done &= ~target_id;
8228 AscSetChipSDTR(iop_base, asyn_sdtr,
8229 tid_no);
8230 boardp->sdtr_data[tid_no] = asyn_sdtr;
8231 }
8232 }
8233 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008234
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008235 q_cntl &= ~QC_MSG_OUT;
8236 asc_dvc->init_sdtr &= ~target_id;
8237 asc_dvc->sdtr_done &= ~target_id;
8238 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8239 } else {
8240 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008241
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008242 q_cntl &= ~QC_MSG_OUT;
8243 asc_dvc->sdtr_done |= target_id;
8244 asc_dvc->init_sdtr |= target_id;
8245 asc_dvc->pci_fix_asyn_xfer &=
8246 ~target_id;
8247 sdtr_data =
8248 AscCalSDTRData(asc_dvc,
8249 ext_msg.xfer_period,
8250 ext_msg.
8251 req_ack_offset);
8252 AscSetChipSDTR(iop_base, sdtr_data,
8253 tid_no);
8254 boardp->sdtr_data[tid_no] = sdtr_data;
8255 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008256
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008257 q_cntl |= QC_MSG_OUT;
8258 AscMsgOutSDTR(asc_dvc,
8259 ext_msg.xfer_period,
8260 ext_msg.req_ack_offset);
8261 asc_dvc->pci_fix_asyn_xfer &=
8262 ~target_id;
8263 sdtr_data =
8264 AscCalSDTRData(asc_dvc,
8265 ext_msg.xfer_period,
8266 ext_msg.
8267 req_ack_offset);
8268 AscSetChipSDTR(iop_base, sdtr_data,
8269 tid_no);
8270 boardp->sdtr_data[tid_no] = sdtr_data;
8271 asc_dvc->sdtr_done |= target_id;
8272 asc_dvc->init_sdtr |= target_id;
8273 }
8274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008275
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008276 AscWriteLramByte(iop_base,
8277 (ushort)(halt_q_addr +
8278 (ushort)ASC_SCSIQ_B_CNTL),
8279 q_cntl);
8280 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8281 return (0);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008282 } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8283 ext_msg.msg_req == EXTENDED_WDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008284 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008285
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008286 ext_msg.wdtr_width = 0;
8287 AscMemWordCopyPtrToLram(iop_base,
8288 ASCV_MSGOUT_BEG,
8289 (uchar *)&ext_msg,
8290 sizeof(EXT_MSG) >> 1);
8291 q_cntl |= QC_MSG_OUT;
8292 AscWriteLramByte(iop_base,
8293 (ushort)(halt_q_addr +
8294 (ushort)ASC_SCSIQ_B_CNTL),
8295 q_cntl);
8296 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8297 return (0);
8298 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008299
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008300 ext_msg.msg_type = MESSAGE_REJECT;
8301 AscMemWordCopyPtrToLram(iop_base,
8302 ASCV_MSGOUT_BEG,
8303 (uchar *)&ext_msg,
8304 sizeof(EXT_MSG) >> 1);
8305 q_cntl |= QC_MSG_OUT;
8306 AscWriteLramByte(iop_base,
8307 (ushort)(halt_q_addr +
8308 (ushort)ASC_SCSIQ_B_CNTL),
8309 q_cntl);
8310 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8311 return (0);
8312 }
8313 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008315 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008316
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008317 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008318
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008319 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008320
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008321 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8322 q_cntl |= QC_MSG_OUT;
8323 AscMsgOutSDTR(asc_dvc,
8324 asc_dvc->
8325 sdtr_period_tbl[(sdtr_data >> 4) &
8326 (uchar)(asc_dvc->
8327 max_sdtr_index -
8328 1)],
8329 (uchar)(sdtr_data & (uchar)
8330 ASC_SYN_MAX_OFFSET));
8331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008332
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008333 AscWriteLramByte(iop_base,
8334 (ushort)(halt_q_addr +
8335 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008336
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008337 tag_code = AscReadLramByte(iop_base,
8338 (ushort)(halt_q_addr + (ushort)
8339 ASC_SCSIQ_B_TAG_CODE));
8340 tag_code &= 0xDC;
8341 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8342 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8343 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008344
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008345 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8346 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008347
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008348 }
8349 AscWriteLramByte(iop_base,
8350 (ushort)(halt_q_addr +
8351 (ushort)ASC_SCSIQ_B_TAG_CODE),
8352 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008353
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008354 q_status = AscReadLramByte(iop_base,
8355 (ushort)(halt_q_addr + (ushort)
8356 ASC_SCSIQ_B_STATUS));
8357 q_status |= (QS_READY | QS_BUSY);
8358 AscWriteLramByte(iop_base,
8359 (ushort)(halt_q_addr +
8360 (ushort)ASC_SCSIQ_B_STATUS),
8361 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008362
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008363 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8364 scsi_busy &= ~target_id;
8365 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008366
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008367 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8368 return (0);
8369 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008370
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008371 AscMemWordCopyPtrFromLram(iop_base,
8372 ASCV_MSGOUT_BEG,
8373 (uchar *)&out_msg,
8374 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008375
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008376 if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008377 (out_msg.msg_len == MS_SDTR_LEN) &&
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008378 (out_msg.msg_req == EXTENDED_SDTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008379
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008380 asc_dvc->init_sdtr &= ~target_id;
8381 asc_dvc->sdtr_done &= ~target_id;
8382 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8383 boardp->sdtr_data[tid_no] = asyn_sdtr;
8384 }
8385 q_cntl &= ~QC_MSG_OUT;
8386 AscWriteLramByte(iop_base,
8387 (ushort)(halt_q_addr +
8388 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8389 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8390 return (0);
8391 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008392
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008393 scsi_status = AscReadLramByte(iop_base,
8394 (ushort)((ushort)halt_q_addr +
8395 (ushort)
8396 ASC_SCSIQ_SCSI_STATUS));
8397 cur_dvc_qng =
8398 AscReadLramByte(iop_base,
8399 (ushort)((ushort)ASC_QADR_BEG +
8400 (ushort)target_ix));
8401 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008403 scsi_busy = AscReadLramByte(iop_base,
8404 (ushort)ASCV_SCSIBUSY_B);
8405 scsi_busy |= target_id;
8406 AscWriteLramByte(iop_base,
8407 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8408 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008410 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8411 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8412 cur_dvc_qng -= 1;
8413 asc_dvc->max_dvc_qng[tid_no] =
8414 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008415
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008416 AscWriteLramByte(iop_base,
8417 (ushort)((ushort)
8418 ASCV_MAX_DVC_QNG_BEG
8419 + (ushort)
8420 tid_no),
8421 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008422
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008423 /*
8424 * Set the device queue depth to the number of
8425 * active requests when the QUEUE FULL condition
8426 * was encountered.
8427 */
8428 boardp->queue_full |= target_id;
8429 boardp->queue_full_cnt[tid_no] =
8430 cur_dvc_qng;
8431 }
8432 }
8433 }
8434 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8435 return (0);
8436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008437#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008438 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8439 uchar q_no;
8440 ushort q_addr;
8441 uchar sg_wk_q_no;
8442 uchar first_sg_wk_q_no;
8443 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8444 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8445 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8446 ushort sg_list_dwords;
8447 ushort sg_entry_cnt;
8448 uchar next_qp;
8449 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008450
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008451 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8452 if (q_no == ASC_QLINK_END) {
8453 return (0);
8454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008455
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008456 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008457
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008458 /*
8459 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8460 * structure pointer using a macro provided by the driver.
8461 * The ASC_SCSI_REQ pointer provides a pointer to the
8462 * host ASC_SG_HEAD structure.
8463 */
8464 /* Read request's SRB pointer. */
8465 scsiq = (ASC_SCSI_Q *)
8466 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8467 (ushort)
8468 (q_addr +
8469 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008470
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008471 /*
8472 * Get request's first and working SG queue.
8473 */
8474 sg_wk_q_no = AscReadLramByte(iop_base,
8475 (ushort)(q_addr +
8476 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008477
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008478 first_sg_wk_q_no = AscReadLramByte(iop_base,
8479 (ushort)(q_addr +
8480 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008481
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008482 /*
8483 * Reset request's working SG queue back to the
8484 * first SG queue.
8485 */
8486 AscWriteLramByte(iop_base,
8487 (ushort)(q_addr +
8488 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8489 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008490
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008491 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008492
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008493 /*
8494 * Set sg_entry_cnt to the number of SG elements
8495 * that will be completed on this interrupt.
8496 *
8497 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8498 * SG elements. The data_cnt and data_addr fields which
8499 * add 1 to the SG element capacity are not used when
8500 * restarting SG handling after a halt.
8501 */
8502 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8503 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008504
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008505 /*
8506 * Keep track of remaining number of SG elements that will
8507 * need to be handled on the next interrupt.
8508 */
8509 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8510 } else {
8511 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8512 scsiq->remain_sg_entry_cnt = 0;
8513 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008514
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008515 /*
8516 * Copy SG elements into the list of allocated SG queues.
8517 *
8518 * Last index completed is saved in scsiq->next_sg_index.
8519 */
8520 next_qp = first_sg_wk_q_no;
8521 q_addr = ASC_QNO_TO_QADDR(next_qp);
8522 scsi_sg_q.sg_head_qp = q_no;
8523 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8524 for (i = 0; i < sg_head->queue_cnt; i++) {
8525 scsi_sg_q.seq_no = i + 1;
8526 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8527 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8528 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8529 /*
8530 * After very first SG queue RISC FW uses next
8531 * SG queue first element then checks sg_list_cnt
8532 * against zero and then decrements, so set
8533 * sg_list_cnt 1 less than number of SG elements
8534 * in each SG queue.
8535 */
8536 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8537 scsi_sg_q.sg_cur_list_cnt =
8538 ASC_SG_LIST_PER_Q - 1;
8539 } else {
8540 /*
8541 * This is the last SG queue in the list of
8542 * allocated SG queues. If there are more
8543 * SG elements than will fit in the allocated
8544 * queues, then set the QCSG_SG_XFER_MORE flag.
8545 */
8546 if (scsiq->remain_sg_entry_cnt != 0) {
8547 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8548 } else {
8549 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8550 }
8551 /* equals sg_entry_cnt * 2 */
8552 sg_list_dwords = sg_entry_cnt << 1;
8553 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8554 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8555 sg_entry_cnt = 0;
8556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008557
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008558 scsi_sg_q.q_no = next_qp;
8559 AscMemWordCopyPtrToLram(iop_base,
8560 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8561 (uchar *)&scsi_sg_q,
8562 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008563
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008564 AscMemDWordCopyPtrToLram(iop_base,
8565 q_addr + ASC_SGQ_LIST_BEG,
8566 (uchar *)&sg_head->
8567 sg_list[scsiq->next_sg_index],
8568 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008569
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008570 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008571
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008572 /*
8573 * If the just completed SG queue contained the
8574 * last SG element, then no more SG queues need
8575 * to be written.
8576 */
8577 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8578 break;
8579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008580
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008581 next_qp = AscReadLramByte(iop_base,
8582 (ushort)(q_addr +
8583 ASC_SCSIQ_B_FWD));
8584 q_addr = ASC_QNO_TO_QADDR(next_qp);
8585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008586
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008587 /*
8588 * Clear the halt condition so the RISC will be restarted
8589 * after the return.
8590 */
8591 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8592 return (0);
8593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008594#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008595 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008596}
8597
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008598static uchar
8599_AscCopyLramScsiDoneQ(PortAddr iop_base,
8600 ushort q_addr,
8601 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008602{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008603 ushort _val;
8604 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008605
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008606 DvcGetQinfo(iop_base,
8607 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8608 (uchar *)scsiq,
8609 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008610
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008611 _val = AscReadLramWord(iop_base,
8612 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8613 scsiq->q_status = (uchar)_val;
8614 scsiq->q_no = (uchar)(_val >> 8);
8615 _val = AscReadLramWord(iop_base,
8616 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8617 scsiq->cntl = (uchar)_val;
8618 sg_queue_cnt = (uchar)(_val >> 8);
8619 _val = AscReadLramWord(iop_base,
8620 (ushort)(q_addr +
8621 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8622 scsiq->sense_len = (uchar)_val;
8623 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008624
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008625 /*
8626 * Read high word of remain bytes from alternate location.
8627 */
8628 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
8629 (ushort)(q_addr +
8630 (ushort)
8631 ASC_SCSIQ_W_ALT_DC1)))
8632 << 16);
8633 /*
8634 * Read low word of remain bytes from original location.
8635 */
8636 scsiq->remain_bytes += AscReadLramWord(iop_base,
8637 (ushort)(q_addr + (ushort)
8638 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008639
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008640 scsiq->remain_bytes &= max_dma_count;
8641 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008642}
8643
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008644static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008645{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008646 uchar next_qp;
8647 uchar n_q_used;
8648 uchar sg_list_qp;
8649 uchar sg_queue_cnt;
8650 uchar q_cnt;
8651 uchar done_q_tail;
8652 uchar tid_no;
8653 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8654 ASC_SCSI_BIT_ID_TYPE target_id;
8655 PortAddr iop_base;
8656 ushort q_addr;
8657 ushort sg_q_addr;
8658 uchar cur_target_qng;
8659 ASC_QDONE_INFO scsiq_buf;
8660 ASC_QDONE_INFO *scsiq;
8661 int false_overrun;
8662 ASC_ISR_CALLBACK asc_isr_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008663
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008664 iop_base = asc_dvc->iop_base;
8665 asc_isr_callback = asc_dvc->isr_callback;
8666 n_q_used = 1;
8667 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
8668 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
8669 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
8670 next_qp = AscReadLramByte(iop_base,
8671 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
8672 if (next_qp != ASC_QLINK_END) {
8673 AscPutVarDoneQTail(iop_base, next_qp);
8674 q_addr = ASC_QNO_TO_QADDR(next_qp);
8675 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
8676 asc_dvc->max_dma_count);
8677 AscWriteLramByte(iop_base,
8678 (ushort)(q_addr +
8679 (ushort)ASC_SCSIQ_B_STATUS),
8680 (uchar)(scsiq->
8681 q_status & (uchar)~(QS_READY |
8682 QS_ABORTED)));
8683 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
8684 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
8685 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
8686 sg_q_addr = q_addr;
8687 sg_list_qp = next_qp;
8688 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
8689 sg_list_qp = AscReadLramByte(iop_base,
8690 (ushort)(sg_q_addr
8691 + (ushort)
8692 ASC_SCSIQ_B_FWD));
8693 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
8694 if (sg_list_qp == ASC_QLINK_END) {
8695 AscSetLibErrorCode(asc_dvc,
8696 ASCQ_ERR_SG_Q_LINKS);
8697 scsiq->d3.done_stat = QD_WITH_ERROR;
8698 scsiq->d3.host_stat =
8699 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
8700 goto FATAL_ERR_QDONE;
8701 }
8702 AscWriteLramByte(iop_base,
8703 (ushort)(sg_q_addr + (ushort)
8704 ASC_SCSIQ_B_STATUS),
8705 QS_FREE);
8706 }
8707 n_q_used = sg_queue_cnt + 1;
8708 AscPutVarDoneQTail(iop_base, sg_list_qp);
8709 }
8710 if (asc_dvc->queue_full_or_busy & target_id) {
8711 cur_target_qng = AscReadLramByte(iop_base,
8712 (ushort)((ushort)
8713 ASC_QADR_BEG
8714 + (ushort)
8715 scsiq->d2.
8716 target_ix));
8717 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
8718 scsi_busy = AscReadLramByte(iop_base, (ushort)
8719 ASCV_SCSIBUSY_B);
8720 scsi_busy &= ~target_id;
8721 AscWriteLramByte(iop_base,
8722 (ushort)ASCV_SCSIBUSY_B,
8723 scsi_busy);
8724 asc_dvc->queue_full_or_busy &= ~target_id;
8725 }
8726 }
8727 if (asc_dvc->cur_total_qng >= n_q_used) {
8728 asc_dvc->cur_total_qng -= n_q_used;
8729 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
8730 asc_dvc->cur_dvc_qng[tid_no]--;
8731 }
8732 } else {
8733 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
8734 scsiq->d3.done_stat = QD_WITH_ERROR;
8735 goto FATAL_ERR_QDONE;
8736 }
8737 if ((scsiq->d2.srb_ptr == 0UL) ||
8738 ((scsiq->q_status & QS_ABORTED) != 0)) {
8739 return (0x11);
8740 } else if (scsiq->q_status == QS_DONE) {
8741 false_overrun = FALSE;
8742 if (scsiq->extra_bytes != 0) {
8743 scsiq->remain_bytes +=
8744 (ADV_DCNT)scsiq->extra_bytes;
8745 }
8746 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
8747 if (scsiq->d3.host_stat ==
8748 QHSTA_M_DATA_OVER_RUN) {
8749 if ((scsiq->
8750 cntl & (QC_DATA_IN | QC_DATA_OUT))
8751 == 0) {
8752 scsiq->d3.done_stat =
8753 QD_NO_ERROR;
8754 scsiq->d3.host_stat =
8755 QHSTA_NO_ERROR;
8756 } else if (false_overrun) {
8757 scsiq->d3.done_stat =
8758 QD_NO_ERROR;
8759 scsiq->d3.host_stat =
8760 QHSTA_NO_ERROR;
8761 }
8762 } else if (scsiq->d3.host_stat ==
8763 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
8764 AscStopChip(iop_base);
8765 AscSetChipControl(iop_base,
8766 (uchar)(CC_SCSI_RESET
8767 | CC_HALT));
8768 DvcDelayNanoSecond(asc_dvc, 60000);
8769 AscSetChipControl(iop_base, CC_HALT);
8770 AscSetChipStatus(iop_base,
8771 CIW_CLR_SCSI_RESET_INT);
8772 AscSetChipStatus(iop_base, 0);
8773 AscSetChipControl(iop_base, 0);
8774 }
8775 }
8776 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8777 (*asc_isr_callback) (asc_dvc, scsiq);
8778 } else {
8779 if ((AscReadLramByte(iop_base,
8780 (ushort)(q_addr + (ushort)
8781 ASC_SCSIQ_CDB_BEG))
8782 == START_STOP)) {
8783 asc_dvc->unit_not_ready &= ~target_id;
8784 if (scsiq->d3.done_stat != QD_NO_ERROR) {
8785 asc_dvc->start_motor &=
8786 ~target_id;
8787 }
8788 }
8789 }
8790 return (1);
8791 } else {
8792 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
8793 FATAL_ERR_QDONE:
8794 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8795 (*asc_isr_callback) (asc_dvc, scsiq);
8796 }
8797 return (0x80);
8798 }
8799 }
8800 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008801}
8802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008803static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008804{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008805 ASC_CS_TYPE chipstat;
8806 PortAddr iop_base;
8807 ushort saved_ram_addr;
8808 uchar ctrl_reg;
8809 uchar saved_ctrl_reg;
8810 int int_pending;
8811 int status;
8812 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008813
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008814 iop_base = asc_dvc->iop_base;
8815 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008816
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008817 if (AscIsIntPending(iop_base) == 0) {
8818 return int_pending;
8819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008820
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008821 if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
8822 || (asc_dvc->isr_callback == 0)
8823 ) {
8824 return (ERR);
8825 }
8826 if (asc_dvc->in_critical_cnt != 0) {
8827 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
8828 return (ERR);
8829 }
8830 if (asc_dvc->is_in_int) {
8831 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
8832 return (ERR);
8833 }
8834 asc_dvc->is_in_int = TRUE;
8835 ctrl_reg = AscGetChipControl(iop_base);
8836 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
8837 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
8838 chipstat = AscGetChipStatus(iop_base);
8839 if (chipstat & CSW_SCSI_RESET_LATCH) {
8840 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
8841 int i = 10;
8842 int_pending = TRUE;
8843 asc_dvc->sdtr_done = 0;
8844 saved_ctrl_reg &= (uchar)(~CC_HALT);
8845 while ((AscGetChipStatus(iop_base) &
8846 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
8847 DvcSleepMilliSecond(100);
8848 }
8849 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
8850 AscSetChipControl(iop_base, CC_HALT);
8851 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
8852 AscSetChipStatus(iop_base, 0);
8853 chipstat = AscGetChipStatus(iop_base);
8854 }
8855 }
8856 saved_ram_addr = AscGetChipLramAddr(iop_base);
8857 host_flag = AscReadLramByte(iop_base,
8858 ASCV_HOST_FLAG_B) &
8859 (uchar)(~ASC_HOST_FLAG_IN_ISR);
8860 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
8861 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
8862 if ((chipstat & CSW_INT_PENDING)
8863 || (int_pending)
8864 ) {
8865 AscAckInterrupt(iop_base);
8866 int_pending = TRUE;
8867 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
8868 if (AscIsrChipHalted(asc_dvc) == ERR) {
8869 goto ISR_REPORT_QDONE_FATAL_ERROR;
8870 } else {
8871 saved_ctrl_reg &= (uchar)(~CC_HALT);
8872 }
8873 } else {
8874 ISR_REPORT_QDONE_FATAL_ERROR:
8875 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
8876 while (((status =
8877 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
8878 }
8879 } else {
8880 do {
8881 if ((status =
8882 AscIsrQDone(asc_dvc)) == 1) {
8883 break;
8884 }
8885 } while (status == 0x11);
8886 }
8887 if ((status & 0x80) != 0)
8888 int_pending = ERR;
8889 }
8890 }
8891 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
8892 AscSetChipLramAddr(iop_base, saved_ram_addr);
8893 AscSetChipControl(iop_base, saved_ctrl_reg);
8894 asc_dvc->is_in_int = FALSE;
8895 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008896}
8897
8898/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008899static uchar _asc_mcode_buf[] = {
8900 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8901 0x00, 0x00, 0x00, 0x00,
8902 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
8903 0x00, 0x00, 0x00, 0x00,
8904 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8905 0x00, 0x00, 0x00, 0x00,
8906 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8907 0x00, 0x00, 0x00, 0x00,
8908 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
8909 0x00, 0xFF, 0x00, 0x00,
8910 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
8911 0x00, 0x00, 0x00, 0x00,
8912 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
8913 0x00, 0x00, 0x00, 0x00,
8914 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
8915 0x00, 0x00, 0x00, 0x00,
8916 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
8917 0x03, 0x23, 0x36, 0x40,
8918 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
8919 0xC2, 0x00, 0x92, 0x80,
8920 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
8921 0xB6, 0x00, 0x92, 0x80,
8922 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
8923 0x92, 0x80, 0x80, 0x62,
8924 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
8925 0xCD, 0x04, 0x4D, 0x00,
8926 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
8927 0xE6, 0x84, 0xD2, 0xC1,
8928 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
8929 0xC6, 0x81, 0xC2, 0x88,
8930 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
8931 0x84, 0x97, 0x07, 0xA6,
8932 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
8933 0xC2, 0x88, 0xCE, 0x00,
8934 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
8935 0x80, 0x63, 0x07, 0xA6,
8936 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
8937 0x34, 0x01, 0x00, 0x33,
8938 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
8939 0x68, 0x98, 0x4D, 0x04,
8940 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
8941 0xF8, 0x88, 0xFB, 0x23,
8942 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
8943 0x00, 0x33, 0x0A, 0x00,
8944 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
8945 0xC2, 0x88, 0xCD, 0x04,
8946 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
8947 0x06, 0xAB, 0x82, 0x01,
8948 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
8949 0x3C, 0x01, 0x00, 0x05,
8950 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
8951 0x15, 0x23, 0xA1, 0x01,
8952 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
8953 0x06, 0x61, 0x00, 0xA0,
8954 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
8955 0xC2, 0x88, 0x06, 0x23,
8956 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
8957 0x57, 0x60, 0x00, 0xA0,
8958 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
8959 0x4B, 0x00, 0x06, 0x61,
8960 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
8961 0x4F, 0x00, 0x84, 0x97,
8962 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
8963 0x48, 0x04, 0x84, 0x80,
8964 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
8965 0x81, 0x73, 0x06, 0x29,
8966 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
8967 0x04, 0x98, 0xF0, 0x80,
8968 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
8969 0x34, 0x02, 0x03, 0xA6,
8970 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
8971 0x46, 0x82, 0xFE, 0x95,
8972 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
8973 0x07, 0xA6, 0x5A, 0x02,
8974 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
8975 0x48, 0x82, 0x60, 0x96,
8976 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
8977 0x04, 0x01, 0x0C, 0xDC,
8978 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
8979 0x6F, 0x00, 0xA5, 0x01,
8980 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
8981 0x02, 0xA6, 0xAA, 0x02,
8982 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
8983 0x01, 0xA6, 0xB4, 0x02,
8984 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
8985 0x80, 0x63, 0x00, 0x43,
8986 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
8987 0x04, 0x61, 0x84, 0x01,
8988 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
8989 0x00, 0x00, 0xEA, 0x82,
8990 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
8991 0x00, 0x33, 0x1F, 0x00,
8992 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
8993 0xB6, 0x2D, 0x01, 0xA6,
8994 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
8995 0x10, 0x03, 0x03, 0xA6,
8996 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
8997 0x7C, 0x95, 0xEE, 0x82,
8998 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
8999 0x04, 0x01, 0x2D, 0xC8,
9000 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
9001 0x05, 0x05, 0x86, 0x98,
9002 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
9003 0x3C, 0x04, 0x06, 0xA6,
9004 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
9005 0x7C, 0x95, 0x32, 0x83,
9006 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
9007 0xEB, 0x04, 0x00, 0x33,
9008 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
9009 0xFF, 0xA2, 0x7A, 0x03,
9010 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
9011 0x00, 0xA2, 0x9A, 0x03,
9012 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
9013 0x01, 0xA6, 0x96, 0x03,
9014 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
9015 0xA4, 0x03, 0x00, 0xA6,
9016 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
9017 0x07, 0xA6, 0xB2, 0x03,
9018 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
9019 0xA8, 0x98, 0x80, 0x42,
9020 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
9021 0xC0, 0x83, 0x00, 0x33,
9022 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
9023 0xA0, 0x01, 0x12, 0x23,
9024 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
9025 0x80, 0x67, 0x05, 0x23,
9026 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
9027 0x06, 0xA6, 0x0A, 0x04,
9028 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
9029 0xF4, 0x83, 0x20, 0x84,
9030 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
9031 0x83, 0x03, 0x80, 0x63,
9032 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
9033 0x38, 0x04, 0x00, 0x33,
9034 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
9035 0x1D, 0x01, 0x06, 0xCC,
9036 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
9037 0xA2, 0x0D, 0x80, 0x63,
9038 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
9039 0x80, 0x63, 0xA3, 0x01,
9040 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
9041 0x76, 0x04, 0xE0, 0x00,
9042 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
9043 0x00, 0x33, 0x1E, 0x00,
9044 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
9045 0x08, 0x23, 0x22, 0xA3,
9046 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
9047 0xC4, 0x04, 0x42, 0x23,
9048 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
9049 0xF8, 0x88, 0x04, 0x98,
9050 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
9051 0x81, 0x62, 0xE8, 0x81,
9052 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
9053 0x00, 0x33, 0x00, 0x81,
9054 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
9055 0xF8, 0x88, 0x04, 0x23,
9056 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
9057 0xF4, 0x04, 0x00, 0x33,
9058 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9059 0x04, 0x23, 0xA0, 0x01,
9060 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9061 0x00, 0xA3, 0x22, 0x05,
9062 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9063 0x46, 0x97, 0xCD, 0x04,
9064 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9065 0x82, 0x01, 0x34, 0x85,
9066 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9067 0x1D, 0x01, 0x04, 0xD6,
9068 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9069 0x49, 0x00, 0x81, 0x01,
9070 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9071 0x49, 0x04, 0x80, 0x01,
9072 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9073 0x01, 0x23, 0xEA, 0x00,
9074 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9075 0x07, 0xA4, 0xF8, 0x05,
9076 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9077 0xC2, 0x88, 0x04, 0xA0,
9078 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9079 0x00, 0xA2, 0xA4, 0x05,
9080 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9081 0x62, 0x97, 0x04, 0x85,
9082 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9083 0xF4, 0x85, 0x03, 0xA0,
9084 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9085 0xCC, 0x86, 0x07, 0xA0,
9086 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9087 0x80, 0x67, 0x80, 0x63,
9088 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9089 0xF8, 0x88, 0x07, 0x23,
9090 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9091 0x00, 0x63, 0x4A, 0x00,
9092 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9093 0x07, 0x41, 0x83, 0x03,
9094 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9095 0x1D, 0x01, 0x01, 0xD6,
9096 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9097 0x07, 0xA6, 0x7C, 0x05,
9098 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9099 0x52, 0x00, 0x06, 0x61,
9100 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9101 0x00, 0x63, 0x1D, 0x01,
9102 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9103 0x07, 0x41, 0x00, 0x63,
9104 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9105 0xDF, 0x00, 0x06, 0xA6,
9106 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9107 0x00, 0x40, 0xC0, 0x20,
9108 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9109 0x06, 0xA6, 0x94, 0x06,
9110 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9111 0x40, 0x0E, 0x80, 0x63,
9112 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9113 0x80, 0x63, 0x00, 0x43,
9114 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9115 0x80, 0x67, 0x40, 0x0E,
9116 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9117 0x07, 0xA6, 0xD6, 0x06,
9118 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9119 0x0A, 0x2B, 0x07, 0xA6,
9120 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9121 0xF4, 0x06, 0xC0, 0x0E,
9122 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9123 0x81, 0x62, 0x04, 0x01,
9124 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9125 0x8C, 0x06, 0x00, 0x33,
9126 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9127 0x80, 0x63, 0x06, 0xA6,
9128 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9129 0x00, 0x00, 0x80, 0x67,
9130 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9131 0xBF, 0x23, 0x04, 0x61,
9132 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9133 0x00, 0x01, 0xF2, 0x00,
9134 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9135 0x80, 0x05, 0x81, 0x05,
9136 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9137 0x70, 0x00, 0x81, 0x01,
9138 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9139 0x70, 0x00, 0x80, 0x01,
9140 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9141 0xF1, 0x00, 0x70, 0x00,
9142 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9143 0x71, 0x04, 0x70, 0x00,
9144 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9145 0xA3, 0x01, 0xA2, 0x01,
9146 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9147 0xC4, 0x07, 0x00, 0x33,
9148 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9149 0x48, 0x00, 0xB0, 0x01,
9150 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9151 0x00, 0xA2, 0xE4, 0x07,
9152 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9153 0x05, 0x05, 0x00, 0x63,
9154 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9155 0x76, 0x08, 0x80, 0x02,
9156 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9157 0x00, 0x02, 0x00, 0xA0,
9158 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9159 0x00, 0x63, 0xF3, 0x04,
9160 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9161 0x00, 0xA2, 0x44, 0x08,
9162 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9163 0x24, 0x08, 0x04, 0x98,
9164 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9165 0x5A, 0x88, 0x02, 0x01,
9166 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9167 0x00, 0xA3, 0x64, 0x08,
9168 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9169 0x06, 0xA6, 0x76, 0x08,
9170 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9171 0x00, 0x63, 0x38, 0x2B,
9172 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9173 0x05, 0x05, 0xB2, 0x09,
9174 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9175 0x80, 0x32, 0x80, 0x36,
9176 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9177 0x40, 0x36, 0x40, 0x3A,
9178 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9179 0x5D, 0x00, 0xFE, 0xC3,
9180 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9181 0xFF, 0xFD, 0x80, 0x73,
9182 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9183 0xA1, 0x23, 0xA1, 0x01,
9184 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9185 0x80, 0x00, 0x03, 0xC2,
9186 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9187 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009188};
9189
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009190static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9191static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009192
9193#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009194static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9195 INQUIRY,
9196 REQUEST_SENSE,
9197 READ_CAPACITY,
9198 READ_TOC,
9199 MODE_SELECT,
9200 MODE_SENSE,
9201 MODE_SELECT_10,
9202 MODE_SENSE_10,
9203 0xFF,
9204 0xFF,
9205 0xFF,
9206 0xFF,
9207 0xFF,
9208 0xFF,
9209 0xFF,
9210 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009211};
9212
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009213static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009214{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009215 PortAddr iop_base;
9216 ulong last_int_level;
9217 int sta;
9218 int n_q_required;
9219 int disable_syn_offset_one_fix;
9220 int i;
9221 ASC_PADDR addr;
9222 ASC_EXE_CALLBACK asc_exe_callback;
9223 ushort sg_entry_cnt = 0;
9224 ushort sg_entry_cnt_minus_one = 0;
9225 uchar target_ix;
9226 uchar tid_no;
9227 uchar sdtr_data;
9228 uchar extra_bytes;
9229 uchar scsi_cmd;
9230 uchar disable_cmd;
9231 ASC_SG_HEAD *sg_head;
9232 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009233
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009234 iop_base = asc_dvc->iop_base;
9235 sg_head = scsiq->sg_head;
9236 asc_exe_callback = asc_dvc->exe_callback;
9237 if (asc_dvc->err_code != 0)
9238 return (ERR);
9239 if (scsiq == (ASC_SCSI_Q *)0L) {
9240 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9241 return (ERR);
9242 }
9243 scsiq->q1.q_no = 0;
9244 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9245 scsiq->q1.extra_bytes = 0;
9246 }
9247 sta = 0;
9248 target_ix = scsiq->q2.target_ix;
9249 tid_no = ASC_TIX_TO_TID(target_ix);
9250 n_q_required = 1;
9251 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9252 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9253 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9254 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9255 AscMsgOutSDTR(asc_dvc,
9256 asc_dvc->
9257 sdtr_period_tbl[(sdtr_data >> 4) &
9258 (uchar)(asc_dvc->
9259 max_sdtr_index -
9260 1)],
9261 (uchar)(sdtr_data & (uchar)
9262 ASC_SYN_MAX_OFFSET));
9263 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9264 }
9265 }
9266 last_int_level = DvcEnterCritical();
9267 if (asc_dvc->in_critical_cnt != 0) {
9268 DvcLeaveCritical(last_int_level);
9269 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9270 return (ERR);
9271 }
9272 asc_dvc->in_critical_cnt++;
9273 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9274 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9275 asc_dvc->in_critical_cnt--;
9276 DvcLeaveCritical(last_int_level);
9277 return (ERR);
9278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009279#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009280 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9281 asc_dvc->in_critical_cnt--;
9282 DvcLeaveCritical(last_int_level);
9283 return (ERR);
9284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009285#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009286 if (sg_entry_cnt == 1) {
9287 scsiq->q1.data_addr =
9288 (ADV_PADDR)sg_head->sg_list[0].addr;
9289 scsiq->q1.data_cnt =
9290 (ADV_DCNT)sg_head->sg_list[0].bytes;
9291 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9292 }
9293 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9294 }
9295 scsi_cmd = scsiq->cdbptr[0];
9296 disable_syn_offset_one_fix = FALSE;
9297 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9298 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9299 if (scsiq->q1.cntl & QC_SG_HEAD) {
9300 data_cnt = 0;
9301 for (i = 0; i < sg_entry_cnt; i++) {
9302 data_cnt +=
9303 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9304 bytes);
9305 }
9306 } else {
9307 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9308 }
9309 if (data_cnt != 0UL) {
9310 if (data_cnt < 512UL) {
9311 disable_syn_offset_one_fix = TRUE;
9312 } else {
9313 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9314 i++) {
9315 disable_cmd =
9316 _syn_offset_one_disable_cmd[i];
9317 if (disable_cmd == 0xFF) {
9318 break;
9319 }
9320 if (scsi_cmd == disable_cmd) {
9321 disable_syn_offset_one_fix =
9322 TRUE;
9323 break;
9324 }
9325 }
9326 }
9327 }
9328 }
9329 if (disable_syn_offset_one_fix) {
9330 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9331 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9332 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9333 } else {
9334 scsiq->q2.tag_code &= 0x27;
9335 }
9336 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9337 if (asc_dvc->bug_fix_cntl) {
9338 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9339 if ((scsi_cmd == READ_6) ||
9340 (scsi_cmd == READ_10)) {
9341 addr =
9342 (ADV_PADDR)le32_to_cpu(sg_head->
9343 sg_list
9344 [sg_entry_cnt_minus_one].
9345 addr) +
9346 (ADV_DCNT)le32_to_cpu(sg_head->
9347 sg_list
9348 [sg_entry_cnt_minus_one].
9349 bytes);
9350 extra_bytes =
9351 (uchar)((ushort)addr & 0x0003);
9352 if ((extra_bytes != 0)
9353 &&
9354 ((scsiq->q2.
9355 tag_code &
9356 ASC_TAG_FLAG_EXTRA_BYTES)
9357 == 0)) {
9358 scsiq->q2.tag_code |=
9359 ASC_TAG_FLAG_EXTRA_BYTES;
9360 scsiq->q1.extra_bytes =
9361 extra_bytes;
9362 data_cnt =
9363 le32_to_cpu(sg_head->
9364 sg_list
9365 [sg_entry_cnt_minus_one].
9366 bytes);
9367 data_cnt -=
9368 (ASC_DCNT) extra_bytes;
9369 sg_head->
9370 sg_list
9371 [sg_entry_cnt_minus_one].
9372 bytes =
9373 cpu_to_le32(data_cnt);
9374 }
9375 }
9376 }
9377 }
9378 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009379#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009380 /*
9381 * Set the sg_entry_cnt to the maximum possible. The rest of
9382 * the SG elements will be copied when the RISC completes the
9383 * SG elements that fit and halts.
9384 */
9385 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9386 sg_entry_cnt = ASC_MAX_SG_LIST;
9387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009388#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009389 n_q_required = AscSgListToQueue(sg_entry_cnt);
9390 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9391 (uint) n_q_required)
9392 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9393 if ((sta =
9394 AscSendScsiQueue(asc_dvc, scsiq,
9395 n_q_required)) == 1) {
9396 asc_dvc->in_critical_cnt--;
9397 if (asc_exe_callback != 0) {
9398 (*asc_exe_callback) (asc_dvc, scsiq);
9399 }
9400 DvcLeaveCritical(last_int_level);
9401 return (sta);
9402 }
9403 }
9404 } else {
9405 if (asc_dvc->bug_fix_cntl) {
9406 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9407 if ((scsi_cmd == READ_6) ||
9408 (scsi_cmd == READ_10)) {
9409 addr =
9410 le32_to_cpu(scsiq->q1.data_addr) +
9411 le32_to_cpu(scsiq->q1.data_cnt);
9412 extra_bytes =
9413 (uchar)((ushort)addr & 0x0003);
9414 if ((extra_bytes != 0)
9415 &&
9416 ((scsiq->q2.
9417 tag_code &
9418 ASC_TAG_FLAG_EXTRA_BYTES)
9419 == 0)) {
9420 data_cnt =
9421 le32_to_cpu(scsiq->q1.
9422 data_cnt);
9423 if (((ushort)data_cnt & 0x01FF)
9424 == 0) {
9425 scsiq->q2.tag_code |=
9426 ASC_TAG_FLAG_EXTRA_BYTES;
9427 data_cnt -= (ASC_DCNT)
9428 extra_bytes;
9429 scsiq->q1.data_cnt =
9430 cpu_to_le32
9431 (data_cnt);
9432 scsiq->q1.extra_bytes =
9433 extra_bytes;
9434 }
9435 }
9436 }
9437 }
9438 }
9439 n_q_required = 1;
9440 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9441 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9442 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9443 n_q_required)) == 1) {
9444 asc_dvc->in_critical_cnt--;
9445 if (asc_exe_callback != 0) {
9446 (*asc_exe_callback) (asc_dvc, scsiq);
9447 }
9448 DvcLeaveCritical(last_int_level);
9449 return (sta);
9450 }
9451 }
9452 }
9453 asc_dvc->in_critical_cnt--;
9454 DvcLeaveCritical(last_int_level);
9455 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009456}
9457
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009458static int
9459AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009460{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009461 PortAddr iop_base;
9462 uchar free_q_head;
9463 uchar next_qp;
9464 uchar tid_no;
9465 uchar target_ix;
9466 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009467
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009468 iop_base = asc_dvc->iop_base;
9469 target_ix = scsiq->q2.target_ix;
9470 tid_no = ASC_TIX_TO_TID(target_ix);
9471 sta = 0;
9472 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9473 if (n_q_required > 1) {
9474 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9475 free_q_head, (uchar)
9476 (n_q_required)))
9477 != (uchar)ASC_QLINK_END) {
9478 asc_dvc->last_q_shortage = 0;
9479 scsiq->sg_head->queue_cnt = n_q_required - 1;
9480 scsiq->q1.q_no = free_q_head;
9481 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9482 free_q_head)) == 1) {
9483 AscPutVarFreeQHead(iop_base, next_qp);
9484 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9485 asc_dvc->cur_dvc_qng[tid_no]++;
9486 }
9487 return (sta);
9488 }
9489 } else if (n_q_required == 1) {
9490 if ((next_qp = AscAllocFreeQueue(iop_base,
9491 free_q_head)) !=
9492 ASC_QLINK_END) {
9493 scsiq->q1.q_no = free_q_head;
9494 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9495 free_q_head)) == 1) {
9496 AscPutVarFreeQHead(iop_base, next_qp);
9497 asc_dvc->cur_total_qng++;
9498 asc_dvc->cur_dvc_qng[tid_no]++;
9499 }
9500 return (sta);
9501 }
9502 }
9503 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009504}
9505
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009506static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009507{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009508 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009509
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009510 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9511 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9512 n_sg_list_qs++;
9513 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009514}
9515
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009516static uint
9517AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009518{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009519 uint cur_used_qs;
9520 uint cur_free_qs;
9521 ASC_SCSI_BIT_ID_TYPE target_id;
9522 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009523
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009524 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9525 tid_no = ASC_TIX_TO_TID(target_ix);
9526 if ((asc_dvc->unit_not_ready & target_id) ||
9527 (asc_dvc->queue_full_or_busy & target_id)) {
9528 return (0);
9529 }
9530 if (n_qs == 1) {
9531 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9532 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9533 } else {
9534 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9535 (uint) ASC_MIN_FREE_Q;
9536 }
9537 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9538 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9539 if (asc_dvc->cur_dvc_qng[tid_no] >=
9540 asc_dvc->max_dvc_qng[tid_no]) {
9541 return (0);
9542 }
9543 return (cur_free_qs);
9544 }
9545 if (n_qs > 1) {
9546 if ((n_qs > asc_dvc->last_q_shortage)
9547 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9548 asc_dvc->last_q_shortage = n_qs;
9549 }
9550 }
9551 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009552}
9553
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009554static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009555{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009556 ushort q_addr;
9557 uchar tid_no;
9558 uchar sdtr_data;
9559 uchar syn_period_ix;
9560 uchar syn_offset;
9561 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009562
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009563 iop_base = asc_dvc->iop_base;
9564 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9565 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9566 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9567 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9568 syn_period_ix =
9569 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9570 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9571 AscMsgOutSDTR(asc_dvc,
9572 asc_dvc->sdtr_period_tbl[syn_period_ix],
9573 syn_offset);
9574 scsiq->q1.cntl |= QC_MSG_OUT;
9575 }
9576 q_addr = ASC_QNO_TO_QADDR(q_no);
9577 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9578 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9579 }
9580 scsiq->q1.status = QS_FREE;
9581 AscMemWordCopyPtrToLram(iop_base,
9582 q_addr + ASC_SCSIQ_CDB_BEG,
9583 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009584
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009585 DvcPutScsiQ(iop_base,
9586 q_addr + ASC_SCSIQ_CPY_BEG,
9587 (uchar *)&scsiq->q1.cntl,
9588 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9589 AscWriteLramWord(iop_base,
9590 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9591 (ushort)(((ushort)scsiq->q1.
9592 q_no << 8) | (ushort)QS_READY));
9593 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009594}
9595
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009596static int
9597AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009598{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009599 int sta;
9600 int i;
9601 ASC_SG_HEAD *sg_head;
9602 ASC_SG_LIST_Q scsi_sg_q;
9603 ASC_DCNT saved_data_addr;
9604 ASC_DCNT saved_data_cnt;
9605 PortAddr iop_base;
9606 ushort sg_list_dwords;
9607 ushort sg_index;
9608 ushort sg_entry_cnt;
9609 ushort q_addr;
9610 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009611
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009612 iop_base = asc_dvc->iop_base;
9613 sg_head = scsiq->sg_head;
9614 saved_data_addr = scsiq->q1.data_addr;
9615 saved_data_cnt = scsiq->q1.data_cnt;
9616 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9617 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009618#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009619 /*
9620 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9621 * then not all SG elements will fit in the allocated queues.
9622 * The rest of the SG elements will be copied when the RISC
9623 * completes the SG elements that fit and halts.
9624 */
9625 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9626 /*
9627 * Set sg_entry_cnt to be the number of SG elements that
9628 * will fit in the allocated SG queues. It is minus 1, because
9629 * the first SG element is handled above. ASC_MAX_SG_LIST is
9630 * already inflated by 1 to account for this. For example it
9631 * may be 50 which is 1 + 7 queues * 7 SG elements.
9632 */
9633 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009634
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009635 /*
9636 * Keep track of remaining number of SG elements that will
9637 * need to be handled from a_isr.c.
9638 */
9639 scsiq->remain_sg_entry_cnt =
9640 sg_head->entry_cnt - ASC_MAX_SG_LIST;
9641 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009642#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009643 /*
9644 * Set sg_entry_cnt to be the number of SG elements that
9645 * will fit in the allocated SG queues. It is minus 1, because
9646 * the first SG element is handled above.
9647 */
9648 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009649#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009651#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009652 if (sg_entry_cnt != 0) {
9653 scsiq->q1.cntl |= QC_SG_HEAD;
9654 q_addr = ASC_QNO_TO_QADDR(q_no);
9655 sg_index = 1;
9656 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
9657 scsi_sg_q.sg_head_qp = q_no;
9658 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
9659 for (i = 0; i < sg_head->queue_cnt; i++) {
9660 scsi_sg_q.seq_no = i + 1;
9661 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
9662 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
9663 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
9664 if (i == 0) {
9665 scsi_sg_q.sg_list_cnt =
9666 ASC_SG_LIST_PER_Q;
9667 scsi_sg_q.sg_cur_list_cnt =
9668 ASC_SG_LIST_PER_Q;
9669 } else {
9670 scsi_sg_q.sg_list_cnt =
9671 ASC_SG_LIST_PER_Q - 1;
9672 scsi_sg_q.sg_cur_list_cnt =
9673 ASC_SG_LIST_PER_Q - 1;
9674 }
9675 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009676#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009677 /*
9678 * This is the last SG queue in the list of
9679 * allocated SG queues. If there are more
9680 * SG elements than will fit in the allocated
9681 * queues, then set the QCSG_SG_XFER_MORE flag.
9682 */
9683 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9684 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
9685 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009686#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009687 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009688#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009690#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009691 sg_list_dwords = sg_entry_cnt << 1;
9692 if (i == 0) {
9693 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
9694 scsi_sg_q.sg_cur_list_cnt =
9695 sg_entry_cnt;
9696 } else {
9697 scsi_sg_q.sg_list_cnt =
9698 sg_entry_cnt - 1;
9699 scsi_sg_q.sg_cur_list_cnt =
9700 sg_entry_cnt - 1;
9701 }
9702 sg_entry_cnt = 0;
9703 }
9704 next_qp = AscReadLramByte(iop_base,
9705 (ushort)(q_addr +
9706 ASC_SCSIQ_B_FWD));
9707 scsi_sg_q.q_no = next_qp;
9708 q_addr = ASC_QNO_TO_QADDR(next_qp);
9709 AscMemWordCopyPtrToLram(iop_base,
9710 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
9711 (uchar *)&scsi_sg_q,
9712 sizeof(ASC_SG_LIST_Q) >> 1);
9713 AscMemDWordCopyPtrToLram(iop_base,
9714 q_addr + ASC_SGQ_LIST_BEG,
9715 (uchar *)&sg_head->
9716 sg_list[sg_index],
9717 sg_list_dwords);
9718 sg_index += ASC_SG_LIST_PER_Q;
9719 scsiq->next_sg_index = sg_index;
9720 }
9721 } else {
9722 scsiq->q1.cntl &= ~QC_SG_HEAD;
9723 }
9724 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
9725 scsiq->q1.data_addr = saved_data_addr;
9726 scsiq->q1.data_cnt = saved_data_cnt;
9727 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009728}
9729
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009730static int
9731AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009732{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009733 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009734
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009735 if (AscHostReqRiscHalt(iop_base)) {
9736 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9737 AscStartChip(iop_base);
9738 return (sta);
9739 }
9740 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009741}
9742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009743static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009744{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009745 ASC_SCSI_BIT_ID_TYPE org_id;
9746 int i;
9747 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009748
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009749 AscSetBank(iop_base, 1);
9750 org_id = AscReadChipDvcID(iop_base);
9751 for (i = 0; i <= ASC_MAX_TID; i++) {
9752 if (org_id == (0x01 << i))
9753 break;
9754 }
9755 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
9756 AscWriteChipDvcID(iop_base, id);
9757 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
9758 AscSetBank(iop_base, 0);
9759 AscSetChipSyn(iop_base, sdtr_data);
9760 if (AscGetChipSyn(iop_base) != sdtr_data) {
9761 sta = FALSE;
9762 }
9763 } else {
9764 sta = FALSE;
9765 }
9766 AscSetBank(iop_base, 1);
9767 AscWriteChipDvcID(iop_base, org_id);
9768 AscSetBank(iop_base, 0);
9769 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009770}
9771
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009772static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009773{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009774 uchar i;
9775 ushort s_addr;
9776 PortAddr iop_base;
9777 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009778
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009779 iop_base = asc_dvc->iop_base;
9780 warn_code = 0;
9781 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
9782 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
9783 64) >> 1)
9784 );
9785 i = ASC_MIN_ACTIVE_QNO;
9786 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
9787 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9788 (uchar)(i + 1));
9789 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9790 (uchar)(asc_dvc->max_total_qng));
9791 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9792 (uchar)i);
9793 i++;
9794 s_addr += ASC_QBLK_SIZE;
9795 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
9796 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9797 (uchar)(i + 1));
9798 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9799 (uchar)(i - 1));
9800 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9801 (uchar)i);
9802 }
9803 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9804 (uchar)ASC_QLINK_END);
9805 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9806 (uchar)(asc_dvc->max_total_qng - 1));
9807 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9808 (uchar)asc_dvc->max_total_qng);
9809 i++;
9810 s_addr += ASC_QBLK_SIZE;
9811 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
9812 i++, s_addr += ASC_QBLK_SIZE) {
9813 AscWriteLramByte(iop_base,
9814 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
9815 AscWriteLramByte(iop_base,
9816 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
9817 AscWriteLramByte(iop_base,
9818 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
9819 }
9820 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009821}
9822
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009823static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009824{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009825 PortAddr iop_base;
9826 int i;
9827 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009829 iop_base = asc_dvc->iop_base;
9830 AscPutRiscVarFreeQHead(iop_base, 1);
9831 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9832 AscPutVarFreeQHead(iop_base, 1);
9833 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9834 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
9835 (uchar)((int)asc_dvc->max_total_qng + 1));
9836 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
9837 (uchar)((int)asc_dvc->max_total_qng + 2));
9838 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
9839 asc_dvc->max_total_qng);
9840 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
9841 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
9842 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
9843 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
9844 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
9845 AscPutQDoneInProgress(iop_base, 0);
9846 lram_addr = ASC_QADR_BEG;
9847 for (i = 0; i < 32; i++, lram_addr += 2) {
9848 AscWriteLramWord(iop_base, lram_addr, 0);
9849 }
9850 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009851}
9852
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009853static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009854{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009855 if (asc_dvc->err_code == 0) {
9856 asc_dvc->err_code = err_code;
9857 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
9858 err_code);
9859 }
9860 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009861}
9862
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009863static uchar
9864AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009865{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009866 EXT_MSG sdtr_buf;
9867 uchar sdtr_period_index;
9868 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009869
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009870 iop_base = asc_dvc->iop_base;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009871 sdtr_buf.msg_type = EXTENDED_MESSAGE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009872 sdtr_buf.msg_len = MS_SDTR_LEN;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009873 sdtr_buf.msg_req = EXTENDED_SDTR;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009874 sdtr_buf.xfer_period = sdtr_period;
9875 sdtr_offset &= ASC_SYN_MAX_OFFSET;
9876 sdtr_buf.req_ack_offset = sdtr_offset;
9877 if ((sdtr_period_index =
9878 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
9879 asc_dvc->max_sdtr_index) {
9880 AscMemWordCopyPtrToLram(iop_base,
9881 ASCV_MSGOUT_BEG,
9882 (uchar *)&sdtr_buf,
9883 sizeof(EXT_MSG) >> 1);
9884 return ((sdtr_period_index << 4) | sdtr_offset);
9885 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009887 sdtr_buf.req_ack_offset = 0;
9888 AscMemWordCopyPtrToLram(iop_base,
9889 ASCV_MSGOUT_BEG,
9890 (uchar *)&sdtr_buf,
9891 sizeof(EXT_MSG) >> 1);
9892 return (0);
9893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009894}
9895
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009896static uchar
9897AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009898{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009899 uchar byte;
9900 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009901
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009902 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
9903 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
9904 ) {
9905 return (0xFF);
9906 }
9907 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
9908 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009909}
9910
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009911static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009912{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009913 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9914 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
9915 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009916}
9917
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009918static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009919{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009920 uchar *period_table;
9921 int max_index;
9922 int min_index;
9923 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009924
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009925 period_table = asc_dvc->sdtr_period_tbl;
9926 max_index = (int)asc_dvc->max_sdtr_index;
9927 min_index = (int)asc_dvc->host_init_sdtr_index;
9928 if ((syn_time <= period_table[max_index])) {
9929 for (i = min_index; i < (max_index - 1); i++) {
9930 if (syn_time <= period_table[i]) {
9931 return ((uchar)i);
9932 }
9933 }
9934 return ((uchar)max_index);
9935 } else {
9936 return ((uchar)(max_index + 1));
9937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009938}
9939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009940static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009941{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009942 ushort q_addr;
9943 uchar next_qp;
9944 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009945
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009946 q_addr = ASC_QNO_TO_QADDR(free_q_head);
9947 q_status = (uchar)AscReadLramByte(iop_base,
9948 (ushort)(q_addr +
9949 ASC_SCSIQ_B_STATUS));
9950 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
9951 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
9952 return (next_qp);
9953 }
9954 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009955}
9956
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009957static uchar
9958AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009959{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009960 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009961
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009962 for (i = 0; i < n_free_q; i++) {
9963 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
9964 == ASC_QLINK_END) {
9965 return (ASC_QLINK_END);
9966 }
9967 }
9968 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009969}
9970
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009971static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009972{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009973 int count = 0;
9974 int sta = 0;
9975 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009976
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009977 if (AscIsChipHalted(iop_base))
9978 return (1);
9979 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
9980 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9981 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
9982 do {
9983 if (AscIsChipHalted(iop_base)) {
9984 sta = 1;
9985 break;
9986 }
9987 DvcSleepMilliSecond(100);
9988 } while (count++ < 20);
9989 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
9990 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009991}
9992
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009993static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009994{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009995 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009997 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
9998 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9999 ASC_STOP_REQ_RISC_STOP);
10000 do {
10001 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
10002 ASC_STOP_ACK_RISC_STOP) {
10003 return (1);
10004 }
10005 DvcSleepMilliSecond(100);
10006 } while (count++ < 20);
10007 }
10008 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010009}
10010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010011static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010012{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010013 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010014}
10015
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010016static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010017{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010018 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010019}
10020
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010021static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010022{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010023 AscSetChipControl(iop_base, 0);
10024 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10025 return (0);
10026 }
10027 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010028}
10029
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010030static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010031{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010032 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010033
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010034 cc_val =
10035 AscGetChipControl(iop_base) &
10036 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
10037 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
10038 AscSetChipIH(iop_base, INS_HALT);
10039 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10040 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
10041 return (0);
10042 }
10043 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010044}
10045
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010046static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010047{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010048 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10049 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
10050 return (1);
10051 }
10052 }
10053 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010054}
10055
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010056static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010057{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010058 AscSetBank(iop_base, 1);
10059 AscWriteChipIH(iop_base, ins_code);
10060 AscSetBank(iop_base, 0);
10061 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010062}
10063
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010064static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010065{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010066 uchar host_flag;
10067 uchar risc_flag;
10068 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010069
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010070 loop = 0;
10071 do {
10072 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10073 if (loop++ > 0x7FFF) {
10074 break;
10075 }
10076 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10077 host_flag =
10078 AscReadLramByte(iop_base,
10079 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10080 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10081 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10082 AscSetChipStatus(iop_base, CIW_INT_ACK);
10083 loop = 0;
10084 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10085 AscSetChipStatus(iop_base, CIW_INT_ACK);
10086 if (loop++ > 3) {
10087 break;
10088 }
10089 }
10090 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10091 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010092}
10093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010094static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010095{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010096 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010097
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010098 cfg = AscGetChipCfgLsw(iop_base);
10099 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10100 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010101}
10102
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010103static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010104{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010105 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010106
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010107 cfg = AscGetChipCfgLsw(iop_base);
10108 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10109 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010110}
10111
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010112static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010113{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010114 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010115
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010116 val = AscGetChipControl(iop_base) &
10117 (~
10118 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10119 CC_CHIP_RESET));
10120 if (bank == 1) {
10121 val |= CC_BANK_ONE;
10122 } else if (bank == 2) {
10123 val |= CC_DIAG | CC_BANK_ONE;
10124 } else {
10125 val &= ~CC_BANK_ONE;
10126 }
10127 AscSetChipControl(iop_base, val);
10128 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010129}
10130
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010131static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010132{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010133 PortAddr iop_base;
10134 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010135
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010136 iop_base = asc_dvc->iop_base;
10137 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10138 && (i-- > 0)) {
10139 DvcSleepMilliSecond(100);
10140 }
10141 AscStopChip(iop_base);
10142 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10143 DvcDelayNanoSecond(asc_dvc, 60000);
10144 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10145 AscSetChipIH(iop_base, INS_HALT);
10146 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10147 AscSetChipControl(iop_base, CC_HALT);
10148 DvcSleepMilliSecond(200);
10149 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10150 AscSetChipStatus(iop_base, 0);
10151 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010152}
10153
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010154static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010155{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010156 if (bus_type & ASC_IS_ISA)
10157 return (ASC_MAX_ISA_DMA_COUNT);
10158 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10159 return (ASC_MAX_VL_DMA_COUNT);
10160 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010161}
10162
10163#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010164static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010165{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010166 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010167
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010168 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10169 if (channel == 0x03)
10170 return (0);
10171 else if (channel == 0x00)
10172 return (7);
10173 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010174}
10175
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010176static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010177{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010178 ushort cfg_lsw;
10179 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010180
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010181 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10182 if (dma_channel == 7)
10183 value = 0x00;
10184 else
10185 value = dma_channel - 4;
10186 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10187 cfg_lsw |= value;
10188 AscSetChipCfgLsw(iop_base, cfg_lsw);
10189 return (AscGetIsaDmaChannel(iop_base));
10190 }
10191 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010192}
10193
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010194static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010195{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010196 speed_value &= 0x07;
10197 AscSetBank(iop_base, 1);
10198 AscWriteChipDmaSpeed(iop_base, speed_value);
10199 AscSetBank(iop_base, 0);
10200 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010201}
10202
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010203static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010204{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010205 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010206
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010207 AscSetBank(iop_base, 1);
10208 speed_value = AscReadChipDmaSpeed(iop_base);
10209 speed_value &= 0x07;
10210 AscSetBank(iop_base, 0);
10211 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010212}
10213#endif /* CONFIG_ISA */
10214
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010215static ushort __devinit AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010216{
Matthew Wilcox9649af32007-07-26 21:51:47 -060010217 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010218
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010219 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -060010220 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010221 return (UW_ERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010222
Matthew Wilcox9649af32007-07-26 21:51:47 -060010223 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010224 warn_code |= AscInitAscDvcVar(asc_dvc);
10225 warn_code |= AscInitFromEEP(asc_dvc);
10226 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010227 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010228 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010229 } else {
10230 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10231 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010232 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010233}
10234
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010235static ushort __devinit AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010236{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010237 ushort warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010238
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010239 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10240 if (asc_dvc->err_code != 0)
10241 return (UW_ERR);
10242 if (AscFindSignature(asc_dvc->iop_base)) {
10243 warn_code |= AscInitFromAscDvcVar(asc_dvc);
10244 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10245 } else {
10246 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10247 }
10248 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010249}
10250
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010251static ushort __devinit AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010252{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010253 PortAddr iop_base;
10254 ushort cfg_msw;
10255 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010256
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010257 iop_base = asc_dvc->iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010258 warn_code = 0;
10259 cfg_msw = AscGetChipCfgMsw(iop_base);
10260 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10261 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10262 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10263 AscSetChipCfgMsw(iop_base, cfg_msw);
10264 }
10265 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10266 asc_dvc->cfg->cmd_qng_enabled) {
10267 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10268 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10269 }
10270 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10271 warn_code |= ASC_WARN_AUTO_CONFIG;
10272 }
10273 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10274 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10275 != asc_dvc->irq_no) {
10276 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10277 }
10278 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010279#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010280 if (asc_dvc->bus_type & ASC_IS_PCI) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010281 struct pci_dev *pdev = to_pci_dev(asc_dvc->cfg->dev);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010282 cfg_msw &= 0xFFC0;
10283 AscSetChipCfgMsw(iop_base, cfg_msw);
10284 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10285 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010286 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
10287 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010288 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10289 asc_dvc->bug_fix_cntl |=
10290 ASC_BUG_FIX_ASYN_USE_SYN;
10291 }
10292 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010293 } else
10294#endif /* CONFIG_PCI */
10295 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010296 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10297 == ASC_CHIP_VER_ASYN_BUG) {
10298 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10299 }
10300 }
10301 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10302 asc_dvc->cfg->chip_scsi_id) {
10303 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010305#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010306 if (asc_dvc->bus_type & ASC_IS_ISA) {
10307 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10308 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010310#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010311 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010312}
10313
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010314static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010315{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010316 ushort warn_code;
10317 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010318
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010319 iop_base = asc_dvc->iop_base;
10320 warn_code = 0;
10321 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10322 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10323 AscResetChipAndScsiBus(asc_dvc);
10324 DvcSleepMilliSecond((ASC_DCNT)
10325 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10326 }
10327 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10328 if (asc_dvc->err_code != 0)
10329 return (UW_ERR);
10330 if (!AscFindSignature(asc_dvc->iop_base)) {
10331 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10332 return (warn_code);
10333 }
10334 AscDisableInterrupt(iop_base);
10335 warn_code |= AscInitLram(asc_dvc);
10336 if (asc_dvc->err_code != 0)
10337 return (UW_ERR);
10338 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10339 (ulong)_asc_mcode_chksum);
10340 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10341 _asc_mcode_size) != _asc_mcode_chksum) {
10342 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10343 return (warn_code);
10344 }
10345 warn_code |= AscInitMicroCodeVar(asc_dvc);
10346 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10347 AscEnableInterrupt(iop_base);
10348 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010349}
10350
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010351static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010352{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010353 int i;
10354 PortAddr iop_base;
10355 ushort warn_code;
10356 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010357
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010358 iop_base = asc_dvc->iop_base;
10359 warn_code = 0;
10360 asc_dvc->err_code = 0;
10361 if ((asc_dvc->bus_type &
10362 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10363 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10364 }
10365 AscSetChipControl(iop_base, CC_HALT);
10366 AscSetChipStatus(iop_base, 0);
10367 asc_dvc->bug_fix_cntl = 0;
10368 asc_dvc->pci_fix_asyn_xfer = 0;
10369 asc_dvc->pci_fix_asyn_xfer_always = 0;
10370 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10371 asc_dvc->sdtr_done = 0;
10372 asc_dvc->cur_total_qng = 0;
10373 asc_dvc->is_in_int = 0;
10374 asc_dvc->in_critical_cnt = 0;
10375 asc_dvc->last_q_shortage = 0;
10376 asc_dvc->use_tagged_qng = 0;
10377 asc_dvc->no_scam = 0;
10378 asc_dvc->unit_not_ready = 0;
10379 asc_dvc->queue_full_or_busy = 0;
10380 asc_dvc->redo_scam = 0;
10381 asc_dvc->res2 = 0;
10382 asc_dvc->host_init_sdtr_index = 0;
10383 asc_dvc->cfg->can_tagged_qng = 0;
10384 asc_dvc->cfg->cmd_qng_enabled = 0;
10385 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10386 asc_dvc->init_sdtr = 0;
10387 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10388 asc_dvc->scsi_reset_wait = 3;
10389 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10390 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10391 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10392 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10393 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10394 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10395 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10396 ASC_LIB_VERSION_MINOR;
10397 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10398 asc_dvc->cfg->chip_version = chip_version;
10399 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10400 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10401 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10402 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10403 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10404 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10405 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10406 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10407 asc_dvc->max_sdtr_index = 7;
10408 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10409 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10410 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10411 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10412 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10413 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10414 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10415 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10416 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10417 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10418 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10419 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10420 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10421 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10422 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10423 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10424 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10425 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10426 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10427 asc_dvc->max_sdtr_index = 15;
10428 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10429 AscSetExtraControl(iop_base,
10430 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10431 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10432 AscSetExtraControl(iop_base,
10433 (SEC_ACTIVE_NEGATE |
10434 SEC_ENABLE_FILTER));
10435 }
10436 }
10437 if (asc_dvc->bus_type == ASC_IS_PCI) {
10438 AscSetExtraControl(iop_base,
10439 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010441
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010442 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010443#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010444 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
Matthew Wilcox59fcf842007-07-26 11:54:15 -040010445 if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
10446 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10447 asc_dvc->bus_type = ASC_IS_ISAPNP;
10448 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010449 asc_dvc->cfg->isa_dma_channel =
10450 (uchar)AscGetIsaDmaChannel(iop_base);
10451 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010452#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010453 for (i = 0; i <= ASC_MAX_TID; i++) {
10454 asc_dvc->cur_dvc_qng[i] = 0;
10455 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10456 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10457 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10458 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10459 }
10460 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010461}
10462
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010463static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010464{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010465 ASCEEP_CONFIG eep_config_buf;
10466 ASCEEP_CONFIG *eep_config;
10467 PortAddr iop_base;
10468 ushort chksum;
10469 ushort warn_code;
10470 ushort cfg_msw, cfg_lsw;
10471 int i;
10472 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010473
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010474 iop_base = asc_dvc->iop_base;
10475 warn_code = 0;
10476 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10477 AscStopQueueExe(iop_base);
10478 if ((AscStopChip(iop_base) == FALSE) ||
10479 (AscGetChipScsiCtrl(iop_base) != 0)) {
10480 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10481 AscResetChipAndScsiBus(asc_dvc);
10482 DvcSleepMilliSecond((ASC_DCNT)
10483 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10484 }
10485 if (AscIsChipHalted(iop_base) == FALSE) {
10486 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10487 return (warn_code);
10488 }
10489 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10490 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10491 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10492 return (warn_code);
10493 }
10494 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10495 cfg_msw = AscGetChipCfgMsw(iop_base);
10496 cfg_lsw = AscGetChipCfgLsw(iop_base);
10497 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10498 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10499 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10500 AscSetChipCfgMsw(iop_base, cfg_msw);
10501 }
10502 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
10503 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
10504 if (chksum == 0) {
10505 chksum = 0xaa55;
10506 }
10507 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10508 warn_code |= ASC_WARN_AUTO_CONFIG;
10509 if (asc_dvc->cfg->chip_version == 3) {
10510 if (eep_config->cfg_lsw != cfg_lsw) {
10511 warn_code |= ASC_WARN_EEPROM_RECOVER;
10512 eep_config->cfg_lsw =
10513 AscGetChipCfgLsw(iop_base);
10514 }
10515 if (eep_config->cfg_msw != cfg_msw) {
10516 warn_code |= ASC_WARN_EEPROM_RECOVER;
10517 eep_config->cfg_msw =
10518 AscGetChipCfgMsw(iop_base);
10519 }
10520 }
10521 }
10522 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
10523 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
10524 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
10525 eep_config->chksum);
10526 if (chksum != eep_config->chksum) {
10527 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
10528 ASC_CHIP_VER_PCI_ULTRA_3050) {
10529 ASC_DBG(1,
10530 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
10531 eep_config->init_sdtr = 0xFF;
10532 eep_config->disc_enable = 0xFF;
10533 eep_config->start_motor = 0xFF;
10534 eep_config->use_cmd_qng = 0;
10535 eep_config->max_total_qng = 0xF0;
10536 eep_config->max_tag_qng = 0x20;
10537 eep_config->cntl = 0xBFFF;
10538 ASC_EEP_SET_CHIP_ID(eep_config, 7);
10539 eep_config->no_scam = 0;
10540 eep_config->adapter_info[0] = 0;
10541 eep_config->adapter_info[1] = 0;
10542 eep_config->adapter_info[2] = 0;
10543 eep_config->adapter_info[3] = 0;
10544 eep_config->adapter_info[4] = 0;
10545 /* Indicate EEPROM-less board. */
10546 eep_config->adapter_info[5] = 0xBB;
10547 } else {
10548 ASC_PRINT
10549 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
10550 write_eep = 1;
10551 warn_code |= ASC_WARN_EEPROM_CHKSUM;
10552 }
10553 }
10554 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
10555 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
10556 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
10557 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
10558 asc_dvc->start_motor = eep_config->start_motor;
10559 asc_dvc->dvc_cntl = eep_config->cntl;
10560 asc_dvc->no_scam = eep_config->no_scam;
10561 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
10562 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
10563 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
10564 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
10565 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
10566 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
10567 if (!AscTestExternalLram(asc_dvc)) {
10568 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
10569 ASC_IS_PCI_ULTRA)) {
10570 eep_config->max_total_qng =
10571 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
10572 eep_config->max_tag_qng =
10573 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
10574 } else {
10575 eep_config->cfg_msw |= 0x0800;
10576 cfg_msw |= 0x0800;
10577 AscSetChipCfgMsw(iop_base, cfg_msw);
10578 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
10579 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
10580 }
10581 } else {
10582 }
10583 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
10584 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
10585 }
10586 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
10587 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
10588 }
10589 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
10590 eep_config->max_tag_qng = eep_config->max_total_qng;
10591 }
10592 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
10593 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
10594 }
10595 asc_dvc->max_total_qng = eep_config->max_total_qng;
10596 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
10597 eep_config->use_cmd_qng) {
10598 eep_config->disc_enable = eep_config->use_cmd_qng;
10599 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10600 }
10601 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
10602 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
10603 }
10604 ASC_EEP_SET_CHIP_ID(eep_config,
10605 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
10606 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
10607 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
10608 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
10609 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
10610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010611
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010612 for (i = 0; i <= ASC_MAX_TID; i++) {
10613 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
10614 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
10615 asc_dvc->cfg->sdtr_period_offset[i] =
10616 (uchar)(ASC_DEF_SDTR_OFFSET |
10617 (asc_dvc->host_init_sdtr_index << 4));
10618 }
10619 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
10620 if (write_eep) {
10621 if ((i =
10622 AscSetEEPConfig(iop_base, eep_config,
10623 asc_dvc->bus_type)) != 0) {
10624 ASC_PRINT1
10625 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
10626 i);
10627 } else {
10628 ASC_PRINT
10629 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
10630 }
10631 }
10632 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010633}
10634
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010635static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010636{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010637 int i;
10638 ushort warn_code;
10639 PortAddr iop_base;
10640 ASC_PADDR phy_addr;
10641 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010643 iop_base = asc_dvc->iop_base;
10644 warn_code = 0;
10645 for (i = 0; i <= ASC_MAX_TID; i++) {
10646 AscPutMCodeInitSDTRAtID(iop_base, i,
10647 asc_dvc->cfg->sdtr_period_offset[i]
10648 );
10649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010650
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010651 AscInitQLinkVar(asc_dvc);
10652 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
10653 asc_dvc->cfg->disc_enable);
10654 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
10655 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010657 /* Align overrun buffer on an 8 byte boundary. */
10658 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
10659 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
10660 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
10661 (uchar *)&phy_addr, 1);
10662 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
10663 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
10664 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010665
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010666 asc_dvc->cfg->mcode_date =
10667 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
10668 asc_dvc->cfg->mcode_version =
10669 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010670
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010671 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10672 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10673 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10674 return (warn_code);
10675 }
10676 if (AscStartChip(iop_base) != 1) {
10677 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10678 return (warn_code);
10679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010680
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010681 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010682}
10683
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010684static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010685{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010686 PortAddr iop_base;
10687 ushort q_addr;
10688 ushort saved_word;
10689 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010690
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010691 iop_base = asc_dvc->iop_base;
10692 sta = 0;
10693 q_addr = ASC_QNO_TO_QADDR(241);
10694 saved_word = AscReadLramWord(iop_base, q_addr);
10695 AscSetChipLramAddr(iop_base, q_addr);
10696 AscSetChipLramData(iop_base, 0x55AA);
10697 DvcSleepMilliSecond(10);
10698 AscSetChipLramAddr(iop_base, q_addr);
10699 if (AscGetChipLramData(iop_base) == 0x55AA) {
10700 sta = 1;
10701 AscWriteLramWord(iop_base, q_addr, saved_word);
10702 }
10703 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010704}
10705
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010706static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010707{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010708 uchar read_back;
10709 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010710
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010711 retry = 0;
10712 while (TRUE) {
10713 AscSetChipEEPCmd(iop_base, cmd_reg);
10714 DvcSleepMilliSecond(1);
10715 read_back = AscGetChipEEPCmd(iop_base);
10716 if (read_back == cmd_reg) {
10717 return (1);
10718 }
10719 if (retry++ > ASC_EEP_MAX_RETRY) {
10720 return (0);
10721 }
10722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010723}
10724
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010725static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010726{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010727 ushort read_back;
10728 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010729
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010730 retry = 0;
10731 while (TRUE) {
10732 AscSetChipEEPData(iop_base, data_reg);
10733 DvcSleepMilliSecond(1);
10734 read_back = AscGetChipEEPData(iop_base);
10735 if (read_back == data_reg) {
10736 return (1);
10737 }
10738 if (retry++ > ASC_EEP_MAX_RETRY) {
10739 return (0);
10740 }
10741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010742}
10743
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010744static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010745{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010746 DvcSleepMilliSecond(1);
10747 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010748}
10749
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010750static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010751{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010752 DvcSleepMilliSecond(20);
10753 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010754}
10755
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010756static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010757{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010758 ushort read_wval;
10759 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010760
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010761 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10762 AscWaitEEPRead();
10763 cmd_reg = addr | ASC_EEP_CMD_READ;
10764 AscWriteEEPCmdReg(iop_base, cmd_reg);
10765 AscWaitEEPRead();
10766 read_wval = AscGetChipEEPData(iop_base);
10767 AscWaitEEPRead();
10768 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010769}
10770
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010771static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010772AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010773{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010774 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010775
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010776 read_wval = AscReadEEPWord(iop_base, addr);
10777 if (read_wval != word_val) {
10778 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
10779 AscWaitEEPRead();
10780 AscWriteEEPDataReg(iop_base, word_val);
10781 AscWaitEEPRead();
10782 AscWriteEEPCmdReg(iop_base,
10783 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
10784 AscWaitEEPWrite();
10785 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10786 AscWaitEEPRead();
10787 return (AscReadEEPWord(iop_base, addr));
10788 }
10789 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010790}
10791
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010792static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010793AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010794{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010795 ushort wval;
10796 ushort sum;
10797 ushort *wbuf;
10798 int cfg_beg;
10799 int cfg_end;
10800 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
10801 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010802
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010803 wbuf = (ushort *)cfg_buf;
10804 sum = 0;
10805 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
10806 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10807 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10808 sum += *wbuf;
10809 }
10810 if (bus_type & ASC_IS_VL) {
10811 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10812 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10813 } else {
10814 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10815 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10816 }
10817 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10818 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
10819 if (s_addr <= uchar_end_in_config) {
10820 /*
10821 * Swap all char fields - must unswap bytes already swapped
10822 * by AscReadEEPWord().
10823 */
10824 *wbuf = le16_to_cpu(wval);
10825 } else {
10826 /* Don't swap word field at the end - cntl field. */
10827 *wbuf = wval;
10828 }
10829 sum += wval; /* Checksum treats all EEPROM data as words. */
10830 }
10831 /*
10832 * Read the checksum word which will be compared against 'sum'
10833 * by the caller. Word field already swapped.
10834 */
10835 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10836 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010837}
10838
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010839static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010840AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010841{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010842 int n_error;
10843 ushort *wbuf;
10844 ushort word;
10845 ushort sum;
10846 int s_addr;
10847 int cfg_beg;
10848 int cfg_end;
10849 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010850
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010851 wbuf = (ushort *)cfg_buf;
10852 n_error = 0;
10853 sum = 0;
10854 /* Write two config words; AscWriteEEPWord() will swap bytes. */
10855 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10856 sum += *wbuf;
10857 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10858 n_error++;
10859 }
10860 }
10861 if (bus_type & ASC_IS_VL) {
10862 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10863 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10864 } else {
10865 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10866 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10867 }
10868 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10869 if (s_addr <= uchar_end_in_config) {
10870 /*
10871 * This is a char field. Swap char fields before they are
10872 * swapped again by AscWriteEEPWord().
10873 */
10874 word = cpu_to_le16(*wbuf);
10875 if (word !=
10876 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
10877 n_error++;
10878 }
10879 } else {
10880 /* Don't swap word field at the end - cntl field. */
10881 if (*wbuf !=
10882 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10883 n_error++;
10884 }
10885 }
10886 sum += *wbuf; /* Checksum calculated from word values. */
10887 }
10888 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
10889 *wbuf = sum;
10890 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
10891 n_error++;
10892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010893
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010894 /* Read EEPROM back again. */
10895 wbuf = (ushort *)cfg_buf;
10896 /*
10897 * Read two config words; Byte-swapping done by AscReadEEPWord().
10898 */
10899 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10900 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
10901 n_error++;
10902 }
10903 }
10904 if (bus_type & ASC_IS_VL) {
10905 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10906 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10907 } else {
10908 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10909 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10910 }
10911 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10912 if (s_addr <= uchar_end_in_config) {
10913 /*
10914 * Swap all char fields. Must unswap bytes already swapped
10915 * by AscReadEEPWord().
10916 */
10917 word =
10918 le16_to_cpu(AscReadEEPWord
10919 (iop_base, (uchar)s_addr));
10920 } else {
10921 /* Don't swap word field at the end - cntl field. */
10922 word = AscReadEEPWord(iop_base, (uchar)s_addr);
10923 }
10924 if (*wbuf != word) {
10925 n_error++;
10926 }
10927 }
10928 /* Read checksum; Byte swapping not needed. */
10929 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
10930 n_error++;
10931 }
10932 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010933}
10934
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010935static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010936AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010937{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010938 int retry;
10939 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010940
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010941 retry = 0;
10942 while (TRUE) {
10943 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
10944 bus_type)) == 0) {
10945 break;
10946 }
10947 if (++retry > ASC_EEP_MAX_RETRY) {
10948 break;
10949 }
10950 }
10951 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010952}
10953
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010954static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010955{
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010956 char type = sdev->type;
10957 ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010958
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010959 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
10960 if (!(asc_dvc->init_sdtr & tid_bits)) {
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010961 if ((type == TYPE_ROM) &&
10962 (strncmp(sdev->vendor, "HP ", 3) == 0)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010963 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
10964 }
10965 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010966 if ((type == TYPE_PROCESSOR) ||
10967 (type == TYPE_SCANNER) || (type == TYPE_ROM) ||
10968 (type == TYPE_TAPE)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010969 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
10970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010971
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010972 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
10973 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010974 sdev->id,
10975 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010976 }
10977 }
10978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010979}
10980
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010981static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010982{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010983 uchar byte_data;
10984 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010985
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010986 if (isodd_word(addr)) {
10987 AscSetChipLramAddr(iop_base, addr - 1);
10988 word_data = AscGetChipLramData(iop_base);
10989 byte_data = (uchar)((word_data >> 8) & 0xFF);
10990 } else {
10991 AscSetChipLramAddr(iop_base, addr);
10992 word_data = AscGetChipLramData(iop_base);
10993 byte_data = (uchar)(word_data & 0xFF);
10994 }
10995 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010996}
Linus Torvalds1da177e2005-04-16 15:20:36 -070010997
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010998static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
10999{
11000 ushort word_data;
11001
11002 AscSetChipLramAddr(iop_base, addr);
11003 word_data = AscGetChipLramData(iop_base);
11004 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011005}
11006
11007#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011008static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011009{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011010 ushort val_low, val_high;
11011 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011012
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011013 AscSetChipLramAddr(iop_base, addr);
11014 val_low = AscGetChipLramData(iop_base);
11015 val_high = AscGetChipLramData(iop_base);
11016 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
11017 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011018}
11019#endif /* CC_VERY_LONG_SG_LIST */
11020
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011021static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011022{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011023 AscSetChipLramAddr(iop_base, addr);
11024 AscSetChipLramData(iop_base, word_val);
11025 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011026}
11027
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011028static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011029{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011030 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011031
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011032 if (isodd_word(addr)) {
11033 addr--;
11034 word_data = AscReadLramWord(iop_base, addr);
11035 word_data &= 0x00FF;
11036 word_data |= (((ushort)byte_val << 8) & 0xFF00);
11037 } else {
11038 word_data = AscReadLramWord(iop_base, addr);
11039 word_data &= 0xFF00;
11040 word_data |= ((ushort)byte_val & 0x00FF);
11041 }
11042 AscWriteLramWord(iop_base, addr, word_data);
11043 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011044}
11045
11046/*
11047 * Copy 2 bytes to LRAM.
11048 *
11049 * The source data is assumed to be in little-endian order in memory
11050 * and is maintained in little-endian order when written to LRAM.
11051 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011052static void
11053AscMemWordCopyPtrToLram(PortAddr iop_base,
11054 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011055{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011056 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011057
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011058 AscSetChipLramAddr(iop_base, s_addr);
11059 for (i = 0; i < 2 * words; i += 2) {
11060 /*
11061 * On a little-endian system the second argument below
11062 * produces a little-endian ushort which is written to
11063 * LRAM in little-endian order. On a big-endian system
11064 * the second argument produces a big-endian ushort which
11065 * is "transparently" byte-swapped by outpw() and written
11066 * in little-endian order to LRAM.
11067 */
11068 outpw(iop_base + IOP_RAM_DATA,
11069 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
11070 }
11071 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011072}
11073
11074/*
11075 * Copy 4 bytes to LRAM.
11076 *
11077 * The source data is assumed to be in little-endian order in memory
11078 * and is maintained in little-endian order when writen to LRAM.
11079 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011080static void
11081AscMemDWordCopyPtrToLram(PortAddr iop_base,
11082 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011083{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011084 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011085
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011086 AscSetChipLramAddr(iop_base, s_addr);
11087 for (i = 0; i < 4 * dwords; i += 4) {
11088 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11089 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11090 }
11091 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011092}
11093
11094/*
11095 * Copy 2 bytes from LRAM.
11096 *
11097 * The source data is assumed to be in little-endian order in LRAM
11098 * and is maintained in little-endian order when written to memory.
11099 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011100static void
11101AscMemWordCopyPtrFromLram(PortAddr iop_base,
11102 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011103{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011104 int i;
11105 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011106
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011107 AscSetChipLramAddr(iop_base, s_addr);
11108 for (i = 0; i < 2 * words; i += 2) {
11109 word = inpw(iop_base + IOP_RAM_DATA);
11110 d_buffer[i] = word & 0xff;
11111 d_buffer[i + 1] = (word >> 8) & 0xff;
11112 }
11113 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011114}
11115
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011116static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011117{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011118 ASC_DCNT sum;
11119 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011120
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011121 sum = 0L;
11122 for (i = 0; i < words; i++, s_addr += 2) {
11123 sum += AscReadLramWord(iop_base, s_addr);
11124 }
11125 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011126}
11127
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011128static void
11129AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011130{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011131 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011132
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011133 AscSetChipLramAddr(iop_base, s_addr);
11134 for (i = 0; i < words; i++) {
11135 AscSetChipLramData(iop_base, set_wval);
11136 }
11137 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011138}
11139
Linus Torvalds1da177e2005-04-16 15:20:36 -070011140/*
11141 * --- Adv Library Functions
11142 */
11143
11144/* a_mcode.h */
11145
11146/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011147static unsigned char _adv_asc3550_buf[] = {
11148 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11149 0x01, 0x00, 0x48, 0xe4,
11150 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11151 0x28, 0x0e, 0x9e, 0xe7,
11152 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11153 0x55, 0xf0, 0x01, 0xf6,
11154 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11155 0x00, 0xec, 0x85, 0xf0,
11156 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11157 0x86, 0xf0, 0xb4, 0x00,
11158 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11159 0xaa, 0x18, 0x02, 0x80,
11160 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11161 0x00, 0x57, 0x01, 0xea,
11162 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11163 0x03, 0xe6, 0xb6, 0x00,
11164 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11165 0x02, 0x4a, 0xb9, 0x54,
11166 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11167 0x3e, 0x00, 0x80, 0x00,
11168 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11169 0x74, 0x01, 0x76, 0x01,
11170 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11171 0x4c, 0x1c, 0xbb, 0x55,
11172 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11173 0x03, 0xf7, 0x06, 0xf7,
11174 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11175 0x30, 0x13, 0x64, 0x15,
11176 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11177 0x04, 0xea, 0x5d, 0xf0,
11178 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11179 0xcc, 0x00, 0x20, 0x01,
11180 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11181 0x40, 0x13, 0x30, 0x1c,
11182 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11183 0x59, 0xf0, 0xa7, 0xf0,
11184 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11185 0xa4, 0x00, 0xb5, 0x00,
11186 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11187 0x14, 0x0e, 0x02, 0x10,
11188 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11189 0x10, 0x15, 0x14, 0x15,
11190 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11191 0x91, 0x44, 0x0a, 0x45,
11192 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11193 0x83, 0x59, 0x05, 0xe6,
11194 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11195 0x02, 0xfa, 0x03, 0xfa,
11196 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11197 0x9e, 0x00, 0xa8, 0x00,
11198 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11199 0x7a, 0x01, 0xc0, 0x01,
11200 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11201 0x69, 0x08, 0xba, 0x08,
11202 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11203 0xf1, 0x10, 0x06, 0x12,
11204 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11205 0x8a, 0x15, 0xc6, 0x17,
11206 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11207 0x0e, 0x47, 0x48, 0x47,
11208 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11209 0x14, 0x56, 0x77, 0x57,
11210 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11211 0xf0, 0x29, 0x02, 0xfe,
11212 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11213 0xfe, 0x80, 0x01, 0xff,
11214 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11215 0x00, 0xfe, 0x57, 0x24,
11216 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11217 0x00, 0x00, 0xff, 0x08,
11218 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11219 0xff, 0xff, 0xff, 0x0f,
11220 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11221 0xfe, 0x04, 0xf7, 0xcf,
11222 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11223 0x0b, 0x3c, 0x2a, 0xfe,
11224 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11225 0xfe, 0xf0, 0x01, 0xfe,
11226 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11227 0x02, 0xfe, 0xd4, 0x0c,
11228 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11229 0x1c, 0x05, 0xfe, 0xa6,
11230 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11231 0xf0, 0xfe, 0x86, 0x02,
11232 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11233 0xfe, 0x46, 0xf0, 0xfe,
11234 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11235 0x44, 0x02, 0xfe, 0x44,
11236 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11237 0xa0, 0x17, 0x06, 0x18,
11238 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11239 0x1e, 0x1c, 0xfe, 0xe9,
11240 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11241 0x0a, 0x6b, 0x01, 0x9e,
11242 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11243 0x01, 0x82, 0xfe, 0xbd,
11244 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11245 0x58, 0x1c, 0x17, 0x06,
11246 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11247 0xfe, 0x94, 0x02, 0xfe,
11248 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11249 0x01, 0xfe, 0x54, 0x0f,
11250 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11251 0x69, 0x10, 0x17, 0x06,
11252 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11253 0xf6, 0xc7, 0x01, 0xfe,
11254 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11255 0x02, 0x29, 0x0a, 0x40,
11256 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11257 0x58, 0x0a, 0x99, 0x01,
11258 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11259 0x2a, 0x46, 0xfe, 0x02,
11260 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11261 0x01, 0xfe, 0x07, 0x4b,
11262 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11263 0xfe, 0x56, 0x03, 0xfe,
11264 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11265 0xfe, 0x9f, 0xf0, 0xfe,
11266 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11267 0x1c, 0xeb, 0x09, 0x04,
11268 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11269 0x01, 0x0e, 0xac, 0x75,
11270 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11271 0xfe, 0x82, 0xf0, 0xfe,
11272 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11273 0x32, 0x1f, 0xfe, 0xb4,
11274 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11275 0x0a, 0xf0, 0xfe, 0x7a,
11276 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11277 0x01, 0x33, 0x8f, 0xfe,
11278 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11279 0xf7, 0xfe, 0x48, 0x1c,
11280 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11281 0x0a, 0xca, 0x01, 0x0e,
11282 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11283 0x2c, 0x01, 0x33, 0x8f,
11284 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11285 0xfe, 0x3c, 0x04, 0x1f,
11286 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11287 0x12, 0x2b, 0xff, 0x02,
11288 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11289 0x22, 0x30, 0x2e, 0xd5,
11290 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11291 0xfe, 0x4c, 0x54, 0x64,
11292 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11293 0xfe, 0x2a, 0x13, 0x2f,
11294 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11295 0xd3, 0xfa, 0xef, 0x86,
11296 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11297 0x1d, 0xfe, 0x1c, 0x12,
11298 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11299 0x70, 0x0c, 0x02, 0x22,
11300 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11301 0x01, 0x33, 0x02, 0x29,
11302 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11303 0x80, 0xfe, 0x31, 0xe4,
11304 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11305 0xfe, 0x70, 0x12, 0x49,
11306 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11307 0x80, 0x05, 0xfe, 0x31,
11308 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11309 0x28, 0xfe, 0x42, 0x12,
11310 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11311 0x11, 0xfe, 0xe3, 0x00,
11312 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11313 0x64, 0x05, 0x83, 0x24,
11314 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11315 0x09, 0x48, 0x01, 0x08,
11316 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11317 0x86, 0x24, 0x06, 0x12,
11318 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11319 0x01, 0xa7, 0x14, 0x92,
11320 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11321 0x02, 0x22, 0x05, 0xfe,
11322 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11323 0x47, 0x01, 0xa7, 0x26,
11324 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11325 0x01, 0xfe, 0xaa, 0x14,
11326 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11327 0x05, 0x50, 0xb4, 0x0c,
11328 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11329 0x13, 0x01, 0xfe, 0x14,
11330 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11331 0xff, 0x02, 0x00, 0x57,
11332 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11333 0x72, 0x06, 0x49, 0x04,
11334 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11335 0x06, 0x11, 0x9a, 0x01,
11336 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11337 0x01, 0xa7, 0xec, 0x72,
11338 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11339 0xfe, 0x0a, 0xf0, 0xfe,
11340 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11341 0x8d, 0x81, 0x02, 0x22,
11342 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11343 0x01, 0x08, 0x15, 0x00,
11344 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11345 0x00, 0x02, 0xfe, 0x32,
11346 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11347 0xfe, 0x1b, 0x00, 0x01,
11348 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11349 0x08, 0x15, 0x06, 0x01,
11350 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11351 0x9a, 0x81, 0x4b, 0x1d,
11352 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11353 0x45, 0xfe, 0x32, 0x12,
11354 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11355 0xfe, 0x32, 0x07, 0x8d,
11356 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11357 0x06, 0x15, 0x19, 0x02,
11358 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11359 0x90, 0x77, 0xfe, 0xca,
11360 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11361 0x10, 0xfe, 0x0e, 0x12,
11362 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11363 0x83, 0xe7, 0xc4, 0xa1,
11364 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11365 0x40, 0x12, 0x58, 0x01,
11366 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11367 0x51, 0x83, 0xfb, 0xfe,
11368 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11369 0xfe, 0x40, 0x50, 0xfe,
11370 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11371 0xfe, 0x2a, 0x12, 0xfe,
11372 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11373 0x85, 0x01, 0xa8, 0xfe,
11374 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11375 0x18, 0x57, 0xfb, 0xfe,
11376 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11377 0x0c, 0x39, 0x18, 0x3a,
11378 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11379 0x11, 0x65, 0xfe, 0x48,
11380 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11381 0xdd, 0xb8, 0xfe, 0x80,
11382 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11383 0xfe, 0x7a, 0x08, 0x8d,
11384 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11385 0x10, 0x61, 0x04, 0x06,
11386 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11387 0x12, 0xfe, 0x2e, 0x1c,
11388 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11389 0x52, 0x12, 0xfe, 0x2c,
11390 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11391 0x08, 0xfe, 0x8a, 0x10,
11392 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11393 0x24, 0x0a, 0xab, 0xfe,
11394 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11395 0x1c, 0x12, 0xb5, 0xfe,
11396 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11397 0x1c, 0x06, 0x16, 0x9d,
11398 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11399 0x14, 0x92, 0x01, 0x33,
11400 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11401 0xfe, 0x74, 0x18, 0x1c,
11402 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11403 0x01, 0xe6, 0x1e, 0x27,
11404 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11405 0x09, 0x04, 0x6a, 0xfe,
11406 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11407 0xfe, 0x83, 0x80, 0xfe,
11408 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11409 0x27, 0xfe, 0x40, 0x59,
11410 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11411 0x7c, 0xbe, 0x54, 0xbf,
11412 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11413 0x79, 0x56, 0x68, 0x57,
11414 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11415 0xa2, 0x23, 0x0c, 0x7b,
11416 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11417 0x16, 0xd7, 0x79, 0x39,
11418 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11419 0xfe, 0x10, 0x58, 0xfe,
11420 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
11421 0x19, 0x16, 0xd7, 0x09,
11422 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
11423 0xfe, 0x10, 0x90, 0xfe,
11424 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
11425 0x11, 0x9b, 0x09, 0x04,
11426 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
11427 0xfe, 0x0c, 0x58, 0xfe,
11428 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
11429 0x0b, 0xfe, 0x1a, 0x12,
11430 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
11431 0x14, 0x7a, 0x01, 0x33,
11432 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
11433 0xfe, 0xed, 0x19, 0xbf,
11434 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
11435 0x34, 0xfe, 0x74, 0x10,
11436 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
11437 0x84, 0x05, 0xcb, 0x1c,
11438 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
11439 0xf0, 0xfe, 0xc4, 0x0a,
11440 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
11441 0xce, 0xf0, 0xfe, 0xca,
11442 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
11443 0x22, 0x00, 0x02, 0x5a,
11444 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
11445 0xfe, 0xd0, 0xf0, 0xfe,
11446 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
11447 0x4c, 0xfe, 0x10, 0x10,
11448 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
11449 0x2a, 0x13, 0xfe, 0x4e,
11450 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
11451 0x16, 0x32, 0x2a, 0x73,
11452 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
11453 0x32, 0x8c, 0xfe, 0x48,
11454 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
11455 0xdb, 0x10, 0x11, 0xfe,
11456 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
11457 0x22, 0x30, 0x2e, 0xd8,
11458 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
11459 0x45, 0x0f, 0xfe, 0x42,
11460 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
11461 0x09, 0x04, 0x0b, 0xfe,
11462 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
11463 0x00, 0x21, 0xfe, 0xa6,
11464 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
11465 0xfe, 0xe2, 0x10, 0x01,
11466 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
11467 0x01, 0x6f, 0x02, 0x29,
11468 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
11469 0x01, 0x86, 0x3e, 0x0b,
11470 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
11471 0x3e, 0x0b, 0x0f, 0xfe,
11472 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
11473 0xe8, 0x59, 0x11, 0x2d,
11474 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
11475 0x04, 0x0b, 0x84, 0x3e,
11476 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
11477 0x09, 0x04, 0x1b, 0xfe,
11478 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
11479 0x1c, 0x1c, 0xfe, 0x9d,
11480 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
11481 0xfe, 0x15, 0x00, 0xfe,
11482 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
11483 0x0f, 0xfe, 0x47, 0x00,
11484 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
11485 0xab, 0x70, 0x05, 0x6b,
11486 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
11487 0x1c, 0x42, 0x59, 0x01,
11488 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
11489 0x00, 0x37, 0x97, 0x01,
11490 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
11491 0x1d, 0xfe, 0xce, 0x45,
11492 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
11493 0x57, 0x05, 0x51, 0xfe,
11494 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
11495 0x46, 0x09, 0x04, 0x1d,
11496 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
11497 0x99, 0x01, 0x0e, 0xfe,
11498 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
11499 0xfe, 0xee, 0x14, 0xee,
11500 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
11501 0x13, 0x02, 0x29, 0x1e,
11502 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
11503 0xce, 0x1e, 0x2d, 0x47,
11504 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
11505 0x12, 0x4d, 0x01, 0xfe,
11506 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
11507 0xf0, 0x0d, 0xfe, 0x02,
11508 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
11509 0xf6, 0xfe, 0x34, 0x01,
11510 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
11511 0xaf, 0xfe, 0x02, 0xea,
11512 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
11513 0x05, 0xfe, 0x38, 0x01,
11514 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
11515 0x0c, 0xfe, 0x62, 0x01,
11516 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
11517 0x03, 0x23, 0x03, 0x1e,
11518 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
11519 0x71, 0x13, 0xfe, 0x24,
11520 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
11521 0xdc, 0xfe, 0x73, 0x57,
11522 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
11523 0x80, 0x5d, 0x03, 0xfe,
11524 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
11525 0x75, 0x03, 0x09, 0x04,
11526 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
11527 0xfe, 0x1e, 0x80, 0xe1,
11528 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
11529 0x90, 0xa3, 0xfe, 0x3c,
11530 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
11531 0x16, 0x2f, 0x07, 0x2d,
11532 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
11533 0xe8, 0x11, 0xfe, 0xe9,
11534 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
11535 0x1e, 0x1c, 0xfe, 0x14,
11536 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
11537 0x09, 0x04, 0x4f, 0xfe,
11538 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
11539 0x40, 0x12, 0x20, 0x63,
11540 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
11541 0x1c, 0x05, 0xfe, 0xac,
11542 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
11543 0xfe, 0xb0, 0x00, 0xfe,
11544 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
11545 0x24, 0x69, 0x12, 0xc9,
11546 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
11547 0x90, 0x4d, 0xfe, 0x91,
11548 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
11549 0xfe, 0x90, 0x4d, 0xfe,
11550 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
11551 0x46, 0x1e, 0x20, 0xed,
11552 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
11553 0x70, 0xfe, 0x14, 0x1c,
11554 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
11555 0xfe, 0x07, 0xe6, 0x1d,
11556 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
11557 0xfa, 0xef, 0xfe, 0x42,
11558 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
11559 0xfe, 0x36, 0x12, 0xf0,
11560 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
11561 0x3d, 0x75, 0x07, 0x10,
11562 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
11563 0x10, 0x07, 0x7e, 0x45,
11564 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
11565 0xfe, 0x01, 0xec, 0x97,
11566 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
11567 0x27, 0x01, 0xda, 0xfe,
11568 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
11569 0xfe, 0x48, 0x12, 0x07,
11570 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
11571 0xfe, 0x3e, 0x11, 0x07,
11572 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
11573 0x11, 0x07, 0x19, 0xfe,
11574 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
11575 0x01, 0x08, 0x8c, 0x43,
11576 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
11577 0x7e, 0x02, 0x29, 0x2b,
11578 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
11579 0xfc, 0x10, 0x09, 0x04,
11580 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
11581 0xc6, 0x10, 0x1e, 0x58,
11582 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
11583 0x54, 0x18, 0x55, 0x23,
11584 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
11585 0xa5, 0xc0, 0x38, 0xc1,
11586 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
11587 0x05, 0xfa, 0x4e, 0xfe,
11588 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
11589 0x0c, 0x56, 0x18, 0x57,
11590 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
11591 0x00, 0x56, 0xfe, 0xa1,
11592 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
11593 0x58, 0xfe, 0x1f, 0x40,
11594 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
11595 0x31, 0x57, 0xfe, 0x44,
11596 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
11597 0x8a, 0x50, 0x05, 0x39,
11598 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
11599 0x12, 0xcd, 0x02, 0x5b,
11600 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
11601 0x2f, 0x07, 0x9b, 0x21,
11602 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
11603 0x39, 0x68, 0x3a, 0xfe,
11604 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
11605 0x51, 0xfe, 0x8e, 0x51,
11606 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
11607 0x01, 0x08, 0x25, 0x32,
11608 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
11609 0x3b, 0x02, 0x44, 0x01,
11610 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
11611 0x01, 0x08, 0x1f, 0xa2,
11612 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
11613 0x00, 0x28, 0x84, 0x49,
11614 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
11615 0x78, 0x3d, 0xfe, 0xda,
11616 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
11617 0x05, 0xc6, 0x28, 0x84,
11618 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
11619 0x14, 0xfe, 0x03, 0x17,
11620 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
11621 0xfe, 0xaa, 0x14, 0x02,
11622 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
11623 0x21, 0x44, 0x01, 0xfe,
11624 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
11625 0xfe, 0x4a, 0xf4, 0x0b,
11626 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
11627 0x85, 0x02, 0x5b, 0x05,
11628 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
11629 0xd8, 0x14, 0x02, 0x5c,
11630 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
11631 0x01, 0x08, 0x23, 0x72,
11632 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
11633 0x12, 0x5e, 0x2b, 0x01,
11634 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
11635 0x1c, 0xfe, 0xff, 0x7f,
11636 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
11637 0x57, 0x48, 0x8b, 0x1c,
11638 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
11639 0x00, 0x57, 0x48, 0x8b,
11640 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
11641 0x03, 0x0a, 0x50, 0x01,
11642 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
11643 0x54, 0xfe, 0x00, 0xf4,
11644 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
11645 0x03, 0x7c, 0x63, 0x27,
11646 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
11647 0xfe, 0x82, 0x4a, 0xfe,
11648 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
11649 0x42, 0x48, 0x5f, 0x60,
11650 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
11651 0x1f, 0xfe, 0xa2, 0x14,
11652 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
11653 0xcc, 0x12, 0x49, 0x04,
11654 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
11655 0xe8, 0x13, 0x3b, 0x13,
11656 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
11657 0xa1, 0xff, 0x02, 0x83,
11658 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
11659 0x13, 0x06, 0xfe, 0x56,
11660 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
11661 0x64, 0x00, 0x17, 0x93,
11662 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
11663 0xc8, 0x00, 0x8e, 0xe4,
11664 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
11665 0x01, 0xba, 0xfe, 0x4e,
11666 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
11667 0xfe, 0x60, 0x14, 0xfe,
11668 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
11669 0xfe, 0x22, 0x13, 0x1c,
11670 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
11671 0xfe, 0x9c, 0x14, 0xb7,
11672 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
11673 0xfe, 0x9c, 0x14, 0xb7,
11674 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
11675 0xfe, 0xb4, 0x56, 0xfe,
11676 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
11677 0xe5, 0x15, 0x0b, 0x01,
11678 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
11679 0x49, 0x01, 0x08, 0x03,
11680 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
11681 0x15, 0x06, 0x01, 0x08,
11682 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
11683 0x4a, 0x01, 0x08, 0x03,
11684 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
11685 0xfe, 0x49, 0xf4, 0x00,
11686 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
11687 0x08, 0x2f, 0x07, 0xfe,
11688 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
11689 0x01, 0x43, 0x1e, 0xcd,
11690 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11691 0xed, 0x88, 0x07, 0x10,
11692 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
11693 0x80, 0x01, 0x0e, 0x88,
11694 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
11695 0x88, 0x03, 0x0a, 0x42,
11696 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11697 0xfe, 0x80, 0x80, 0xf2,
11698 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
11699 0x01, 0x82, 0x03, 0x17,
11700 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
11701 0xfe, 0x24, 0x1c, 0xfe,
11702 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
11703 0x91, 0x1d, 0x66, 0xfe,
11704 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
11705 0xda, 0x10, 0x17, 0x10,
11706 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
11707 0x05, 0xfe, 0x66, 0x01,
11708 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
11709 0xfe, 0x3c, 0x50, 0x66,
11710 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
11711 0x40, 0x16, 0xfe, 0xb6,
11712 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
11713 0x10, 0x71, 0xfe, 0x83,
11714 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
11715 0xfe, 0x62, 0x16, 0xfe,
11716 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
11717 0xfe, 0x98, 0xe7, 0x00,
11718 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
11719 0xfe, 0x30, 0xbc, 0xfe,
11720 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
11721 0xc5, 0x90, 0xfe, 0x9a,
11722 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
11723 0x42, 0x10, 0xfe, 0x02,
11724 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
11725 0xfe, 0x1d, 0xf7, 0x4f,
11726 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
11727 0x47, 0xfe, 0x83, 0x58,
11728 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
11729 0xfe, 0xdd, 0x00, 0x63,
11730 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
11731 0x06, 0x37, 0x95, 0xa9,
11732 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
11733 0x18, 0x1c, 0x1a, 0x5d,
11734 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
11735 0xe1, 0x10, 0x78, 0x2c,
11736 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
11737 0x13, 0x3c, 0x8a, 0x0a,
11738 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
11739 0xe3, 0xfe, 0x00, 0xcc,
11740 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
11741 0x0e, 0xf2, 0x01, 0x6f,
11742 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
11743 0xf6, 0xfe, 0xd6, 0xf0,
11744 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
11745 0x15, 0x00, 0x59, 0x76,
11746 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
11747 0x11, 0x2d, 0x01, 0x6f,
11748 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
11749 0xc8, 0xfe, 0x48, 0x55,
11750 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
11751 0x99, 0x01, 0x0e, 0xf0,
11752 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
11753 0x75, 0x03, 0x0a, 0x42,
11754 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
11755 0x0e, 0x73, 0x75, 0x03,
11756 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
11757 0xfe, 0x3a, 0x45, 0x5b,
11758 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
11759 0xfe, 0x02, 0xe6, 0x1b,
11760 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
11761 0xfe, 0x94, 0x00, 0xfe,
11762 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
11763 0xe6, 0x2c, 0xfe, 0x4e,
11764 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
11765 0x03, 0x07, 0x7a, 0xfe,
11766 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
11767 0x07, 0x1b, 0xfe, 0x5a,
11768 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
11769 0x24, 0x2c, 0xdc, 0x07,
11770 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
11771 0x9f, 0xad, 0x03, 0x14,
11772 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
11773 0x03, 0x25, 0xfe, 0xca,
11774 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
11775 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011776};
11777
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011778static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
11779static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011780
11781/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011782static unsigned char _adv_asc38C0800_buf[] = {
11783 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
11784 0x01, 0x00, 0x48, 0xe4,
11785 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
11786 0x1c, 0x0f, 0x00, 0xf6,
11787 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
11788 0x09, 0xe7, 0x55, 0xf0,
11789 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
11790 0x18, 0xf4, 0x08, 0x00,
11791 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
11792 0x86, 0xf0, 0xb1, 0xf0,
11793 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
11794 0x3c, 0x00, 0xbb, 0x00,
11795 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
11796 0xba, 0x13, 0x18, 0x40,
11797 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
11798 0x6e, 0x01, 0x74, 0x01,
11799 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
11800 0xc0, 0x00, 0x01, 0x01,
11801 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
11802 0x08, 0x12, 0x02, 0x4a,
11803 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
11804 0x5d, 0xf0, 0x02, 0xfa,
11805 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
11806 0x68, 0x01, 0x6a, 0x01,
11807 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
11808 0x06, 0x13, 0x4c, 0x1c,
11809 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
11810 0x0f, 0x00, 0x47, 0x00,
11811 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
11812 0x4e, 0x1c, 0x10, 0x44,
11813 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
11814 0x05, 0x00, 0x34, 0x00,
11815 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
11816 0x42, 0x0c, 0x12, 0x0f,
11817 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
11818 0x00, 0x4e, 0x42, 0x54,
11819 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11820 0x59, 0xf0, 0xb8, 0xf0,
11821 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
11822 0x19, 0x00, 0x33, 0x00,
11823 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
11824 0xe7, 0x00, 0xe2, 0x03,
11825 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
11826 0x12, 0x13, 0x24, 0x14,
11827 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
11828 0x36, 0x1c, 0x08, 0x44,
11829 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
11830 0x3a, 0x55, 0x83, 0x55,
11831 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
11832 0x0c, 0xf0, 0x04, 0xf8,
11833 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
11834 0xa8, 0x00, 0xaa, 0x00,
11835 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
11836 0xc4, 0x01, 0xc6, 0x01,
11837 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
11838 0x68, 0x08, 0x69, 0x08,
11839 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
11840 0xed, 0x10, 0xf1, 0x10,
11841 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
11842 0x1e, 0x13, 0x46, 0x14,
11843 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
11844 0xca, 0x18, 0xe6, 0x19,
11845 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
11846 0xf0, 0x2b, 0x02, 0xfe,
11847 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
11848 0xfe, 0x84, 0x01, 0xff,
11849 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11850 0x00, 0xfe, 0x57, 0x24,
11851 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
11852 0x00, 0x00, 0xff, 0x08,
11853 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11854 0xff, 0xff, 0xff, 0x11,
11855 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11856 0xfe, 0x04, 0xf7, 0xd6,
11857 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
11858 0x0a, 0x42, 0x2c, 0xfe,
11859 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
11860 0xfe, 0xf4, 0x01, 0xfe,
11861 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
11862 0x02, 0xfe, 0xc8, 0x0d,
11863 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11864 0x1c, 0x03, 0xfe, 0xa6,
11865 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
11866 0xf0, 0xfe, 0x8a, 0x02,
11867 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
11868 0xfe, 0x46, 0xf0, 0xfe,
11869 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11870 0x48, 0x02, 0xfe, 0x44,
11871 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
11872 0xaa, 0x18, 0x06, 0x14,
11873 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
11874 0x1e, 0x1c, 0xfe, 0xe9,
11875 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
11876 0x09, 0x70, 0x01, 0xa8,
11877 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
11878 0x01, 0x87, 0xfe, 0xbd,
11879 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11880 0x58, 0x1c, 0x18, 0x06,
11881 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
11882 0xfe, 0x98, 0x02, 0xfe,
11883 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
11884 0x01, 0xfe, 0x48, 0x10,
11885 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
11886 0x69, 0x10, 0x18, 0x06,
11887 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
11888 0xf6, 0xce, 0x01, 0xfe,
11889 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
11890 0x82, 0x16, 0x02, 0x2b,
11891 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
11892 0xfe, 0x41, 0x58, 0x09,
11893 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
11894 0x82, 0x16, 0x02, 0x2b,
11895 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
11896 0xfe, 0x77, 0x57, 0xfe,
11897 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
11898 0xfe, 0x40, 0x1c, 0x1c,
11899 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
11900 0x03, 0xfe, 0x11, 0xf0,
11901 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
11902 0xfe, 0x11, 0x00, 0x02,
11903 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
11904 0x21, 0x22, 0xa3, 0xb7,
11905 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
11906 0x12, 0xd1, 0x1c, 0xd9,
11907 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
11908 0xfe, 0xe4, 0x00, 0x27,
11909 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
11910 0x06, 0xf0, 0xfe, 0xc8,
11911 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
11912 0x70, 0x28, 0x17, 0xfe,
11913 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
11914 0xf9, 0x2c, 0x99, 0x19,
11915 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
11916 0x74, 0x01, 0xaf, 0x8c,
11917 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
11918 0x8d, 0x51, 0x64, 0x79,
11919 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
11920 0xfe, 0x6a, 0x02, 0x02,
11921 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
11922 0xfe, 0x3c, 0x04, 0x3b,
11923 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
11924 0x00, 0x10, 0x01, 0x0b,
11925 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
11926 0xfe, 0x4c, 0x44, 0xfe,
11927 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
11928 0xda, 0x4f, 0x79, 0x2a,
11929 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
11930 0xfe, 0x2a, 0x13, 0x32,
11931 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
11932 0x54, 0x6b, 0xda, 0xfe,
11933 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
11934 0x08, 0x13, 0x32, 0x07,
11935 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
11936 0x08, 0x05, 0x06, 0x4d,
11937 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
11938 0x2d, 0x12, 0xfe, 0xe6,
11939 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
11940 0x02, 0x2b, 0xfe, 0x42,
11941 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
11942 0xfe, 0x87, 0x80, 0xfe,
11943 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
11944 0x07, 0x19, 0xfe, 0x7c,
11945 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
11946 0x17, 0xfe, 0x90, 0x05,
11947 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
11948 0xa0, 0x00, 0x28, 0xfe,
11949 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
11950 0x34, 0xfe, 0x89, 0x48,
11951 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
11952 0x12, 0xfe, 0xe3, 0x00,
11953 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11954 0x70, 0x05, 0x88, 0x25,
11955 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
11956 0x09, 0x48, 0xff, 0x02,
11957 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
11958 0x08, 0x53, 0x05, 0xcb,
11959 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
11960 0x05, 0x1b, 0xfe, 0x22,
11961 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
11962 0x0d, 0x00, 0x01, 0x36,
11963 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
11964 0x03, 0x5c, 0x28, 0xfe,
11965 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
11966 0x05, 0x1f, 0xfe, 0x02,
11967 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
11968 0x01, 0x4b, 0x12, 0xfe,
11969 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
11970 0x12, 0x03, 0x45, 0x28,
11971 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
11972 0x43, 0x48, 0xc4, 0xcc,
11973 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
11974 0x6e, 0x41, 0x01, 0xb2,
11975 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
11976 0xfe, 0xcc, 0x15, 0x1d,
11977 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
11978 0x45, 0xc1, 0x0c, 0x45,
11979 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
11980 0xe2, 0x00, 0x27, 0xdb,
11981 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
11982 0xfe, 0x06, 0xf0, 0xfe,
11983 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
11984 0x16, 0x19, 0x01, 0x0b,
11985 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
11986 0xfe, 0x99, 0xa4, 0x01,
11987 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
11988 0x12, 0x08, 0x05, 0x1a,
11989 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
11990 0x0b, 0x16, 0x00, 0x01,
11991 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
11992 0xe2, 0x6c, 0x58, 0xbe,
11993 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
11994 0xfe, 0x09, 0x6f, 0xba,
11995 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
11996 0xfe, 0x54, 0x07, 0x1c,
11997 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
11998 0x07, 0x02, 0x24, 0x01,
11999 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
12000 0x2c, 0x90, 0xfe, 0xae,
12001 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
12002 0x37, 0x22, 0x20, 0x07,
12003 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
12004 0xfe, 0x06, 0x10, 0xfe,
12005 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
12006 0x37, 0x01, 0xb3, 0xb8,
12007 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
12008 0x50, 0xfe, 0x44, 0x51,
12009 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
12010 0x14, 0x5f, 0xfe, 0x0c,
12011 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
12012 0x14, 0x3e, 0xfe, 0x4a,
12013 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
12014 0x90, 0x0c, 0x60, 0x14,
12015 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
12016 0xfe, 0x44, 0x90, 0xfe,
12017 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
12018 0x0c, 0x5e, 0x14, 0x5f,
12019 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
12020 0x14, 0x3c, 0x21, 0x0c,
12021 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
12022 0x27, 0xdd, 0xfe, 0x9e,
12023 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
12024 0x9a, 0x08, 0xc6, 0xfe,
12025 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
12026 0x95, 0x86, 0x02, 0x24,
12027 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
12028 0x06, 0xfe, 0x10, 0x12,
12029 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
12030 0x1c, 0x02, 0xfe, 0x18,
12031 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
12032 0x2c, 0x1c, 0xfe, 0xaa,
12033 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
12034 0xde, 0x09, 0xfe, 0xb7,
12035 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
12036 0xfe, 0xf1, 0x18, 0xfe,
12037 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
12038 0x14, 0x59, 0xfe, 0x95,
12039 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
12040 0xfe, 0xf0, 0x08, 0xb5,
12041 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
12042 0x0b, 0xb6, 0xfe, 0xbf,
12043 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
12044 0x12, 0xc2, 0xfe, 0xd2,
12045 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
12046 0x06, 0x17, 0x85, 0xc5,
12047 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
12048 0x9d, 0x01, 0x36, 0x10,
12049 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
12050 0x98, 0x80, 0xfe, 0x19,
12051 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
12052 0xfe, 0x44, 0x54, 0xbe,
12053 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
12054 0x02, 0x4a, 0x08, 0x05,
12055 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
12056 0x9c, 0x3c, 0xfe, 0x6c,
12057 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
12058 0x3b, 0x40, 0x03, 0x49,
12059 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
12060 0x8f, 0xfe, 0xe3, 0x54,
12061 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
12062 0xda, 0x09, 0xfe, 0x8b,
12063 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
12064 0x0a, 0x3a, 0x49, 0x3b,
12065 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
12066 0xad, 0xfe, 0x01, 0x59,
12067 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
12068 0x49, 0x8f, 0xfe, 0xe3,
12069 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
12070 0x4a, 0x3a, 0x49, 0x3b,
12071 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
12072 0x02, 0x4a, 0x08, 0x05,
12073 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
12074 0xb7, 0xfe, 0x03, 0xa1,
12075 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12076 0xfe, 0x86, 0x91, 0x6a,
12077 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12078 0x61, 0x0c, 0x7f, 0x14,
12079 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12080 0x9b, 0x2e, 0x9c, 0x3c,
12081 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12082 0xfa, 0x3c, 0x01, 0xef,
12083 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12084 0xe4, 0x08, 0x05, 0x1f,
12085 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12086 0x03, 0x5e, 0x29, 0x5f,
12087 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12088 0xf4, 0x09, 0x08, 0x05,
12089 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12090 0x81, 0x50, 0xfe, 0x10,
12091 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12092 0x08, 0x09, 0x12, 0xa6,
12093 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12094 0x08, 0x09, 0xfe, 0x0c,
12095 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12096 0x08, 0x05, 0x0a, 0xfe,
12097 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12098 0xf0, 0xe2, 0x15, 0x7e,
12099 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12100 0x57, 0x3d, 0xfe, 0xed,
12101 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12102 0x00, 0xff, 0x35, 0xfe,
12103 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12104 0x1e, 0x19, 0x8a, 0x03,
12105 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12106 0xfe, 0xd1, 0xf0, 0xfe,
12107 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12108 0x10, 0xfe, 0xce, 0xf0,
12109 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12110 0x10, 0xfe, 0x22, 0x00,
12111 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12112 0x02, 0x65, 0xfe, 0xd0,
12113 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12114 0x0b, 0x10, 0x58, 0xfe,
12115 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12116 0x12, 0x00, 0x2c, 0x0f,
12117 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12118 0x0c, 0xbc, 0x17, 0x34,
12119 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12120 0x0c, 0x1c, 0x34, 0x94,
12121 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12122 0x4b, 0xfe, 0xdb, 0x10,
12123 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12124 0x89, 0xf0, 0x24, 0x33,
12125 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12126 0x33, 0x31, 0xdf, 0xbc,
12127 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12128 0x17, 0xfe, 0x2c, 0x0d,
12129 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12130 0x12, 0x55, 0xfe, 0x28,
12131 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12132 0x44, 0xfe, 0x28, 0x00,
12133 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12134 0x0f, 0x64, 0x12, 0x2f,
12135 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12136 0x0a, 0xfe, 0xb4, 0x10,
12137 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12138 0xfe, 0x34, 0x46, 0xac,
12139 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12140 0x37, 0x01, 0xf5, 0x01,
12141 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12142 0xfe, 0x2e, 0x03, 0x08,
12143 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12144 0x1a, 0xfe, 0x58, 0x12,
12145 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12146 0xfe, 0x50, 0x0d, 0xfe,
12147 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12148 0xfe, 0xa9, 0x10, 0x10,
12149 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12150 0xfe, 0x13, 0x00, 0xfe,
12151 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12152 0x24, 0x00, 0x8c, 0xb5,
12153 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12154 0xfe, 0x9d, 0x41, 0xfe,
12155 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12156 0xb4, 0x15, 0xfe, 0x31,
12157 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12158 0xec, 0xd0, 0xfc, 0x44,
12159 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12160 0x4b, 0x91, 0xfe, 0x75,
12161 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12162 0x0e, 0xfe, 0x44, 0x48,
12163 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12164 0xfe, 0x41, 0x58, 0x09,
12165 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12166 0x2e, 0x03, 0x09, 0x5d,
12167 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12168 0xce, 0x47, 0xfe, 0xad,
12169 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12170 0x59, 0x13, 0x9f, 0x13,
12171 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12172 0xe0, 0x0e, 0x0f, 0x06,
12173 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12174 0x3a, 0x01, 0x56, 0xfe,
12175 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12176 0x20, 0x4f, 0xfe, 0x05,
12177 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12178 0x48, 0xf4, 0x0d, 0xfe,
12179 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12180 0x15, 0x1a, 0x39, 0xa0,
12181 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12182 0x0c, 0xfe, 0x60, 0x01,
12183 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12184 0x06, 0x13, 0x2f, 0x12,
12185 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12186 0x22, 0x9f, 0xb7, 0x13,
12187 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12188 0xa0, 0xb4, 0xfe, 0xd9,
12189 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12190 0xc3, 0xfe, 0x03, 0xdc,
12191 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12192 0xfe, 0x00, 0xcc, 0x04,
12193 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12194 0xfe, 0x1c, 0x80, 0x07,
12195 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12196 0xfe, 0x0c, 0x90, 0xfe,
12197 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12198 0x0a, 0xfe, 0x3c, 0x50,
12199 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12200 0x16, 0x08, 0x05, 0x1b,
12201 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12202 0xfe, 0x2c, 0x13, 0x01,
12203 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12204 0x0c, 0xfe, 0x64, 0x01,
12205 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12206 0x80, 0x8d, 0xfe, 0x01,
12207 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12208 0x22, 0x20, 0xfb, 0x79,
12209 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12210 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012212 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12213 0xb2, 0x00, 0xfe, 0x09,
12214 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12215 0x45, 0x0f, 0x46, 0x52,
12216 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12217 0x0f, 0x44, 0x11, 0x0f,
12218 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12219 0x25, 0x11, 0x13, 0x20,
12220 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12221 0x56, 0xfe, 0xd6, 0xf0,
12222 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12223 0x18, 0x1c, 0x04, 0x42,
12224 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12225 0xf5, 0x13, 0x04, 0x01,
12226 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12227 0x13, 0x32, 0x07, 0x2f,
12228 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12229 0x41, 0x48, 0xfe, 0x45,
12230 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12231 0x07, 0x11, 0xac, 0x09,
12232 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12233 0x82, 0x4e, 0xfe, 0x14,
12234 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12235 0xfe, 0x01, 0xec, 0xa2,
12236 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12237 0x2a, 0x01, 0xe3, 0xfe,
12238 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12239 0xfe, 0x48, 0x12, 0x07,
12240 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12241 0xfe, 0x32, 0x12, 0x07,
12242 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12243 0x1f, 0xfe, 0x12, 0x12,
12244 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12245 0x94, 0x4b, 0x04, 0x2d,
12246 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12247 0x32, 0x07, 0xa6, 0xfe,
12248 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12249 0x5a, 0xfe, 0x72, 0x12,
12250 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12251 0xfe, 0x26, 0x13, 0x03,
12252 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12253 0x0c, 0x7f, 0x0c, 0x80,
12254 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12255 0x3c, 0xfe, 0x04, 0x55,
12256 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12257 0x91, 0x10, 0x03, 0x3f,
12258 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12259 0x88, 0x9b, 0x2e, 0x9c,
12260 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12261 0x56, 0x0c, 0x5e, 0x14,
12262 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12263 0x03, 0x60, 0x29, 0x61,
12264 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12265 0x50, 0xfe, 0xc6, 0x50,
12266 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12267 0x29, 0x3e, 0xfe, 0x40,
12268 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12269 0x2d, 0x01, 0x0b, 0x1d,
12270 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12271 0x72, 0x01, 0xaf, 0x1e,
12272 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12273 0x0a, 0x55, 0x35, 0xfe,
12274 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12275 0x02, 0x72, 0xfe, 0x19,
12276 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12277 0x1d, 0xe8, 0x33, 0x31,
12278 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12279 0x0b, 0x1c, 0x34, 0x1d,
12280 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12281 0x33, 0x31, 0xfe, 0xe8,
12282 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12283 0x05, 0x1f, 0x35, 0xa9,
12284 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12285 0x14, 0x01, 0xaf, 0x8c,
12286 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12287 0x03, 0x45, 0x28, 0x35,
12288 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12289 0x03, 0x5c, 0xc1, 0x0c,
12290 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12291 0x89, 0x01, 0x0b, 0x1c,
12292 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12293 0xfe, 0x42, 0x58, 0xf1,
12294 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12295 0xf4, 0x06, 0xea, 0x32,
12296 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12297 0x01, 0x0b, 0x26, 0x89,
12298 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12299 0x26, 0xfe, 0xd4, 0x13,
12300 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12301 0x13, 0x1c, 0xfe, 0xd0,
12302 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12303 0x0f, 0x71, 0xff, 0x02,
12304 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12305 0x00, 0x5c, 0x04, 0x0f,
12306 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12307 0xfe, 0x00, 0x5c, 0x04,
12308 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12309 0x02, 0x00, 0x57, 0x52,
12310 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12311 0x87, 0x04, 0xfe, 0x03,
12312 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12313 0xfe, 0x00, 0x7d, 0xfe,
12314 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12315 0x14, 0x5f, 0x57, 0x3f,
12316 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12317 0x5a, 0x8d, 0x04, 0x01,
12318 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12319 0xfe, 0x96, 0x15, 0x33,
12320 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12321 0x0a, 0xfe, 0xc1, 0x59,
12322 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12323 0x21, 0x69, 0x1a, 0xee,
12324 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12325 0x30, 0xfe, 0x78, 0x10,
12326 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12327 0x98, 0xfe, 0x30, 0x00,
12328 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12329 0x98, 0xfe, 0x64, 0x00,
12330 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12331 0x10, 0x69, 0x06, 0xfe,
12332 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12333 0x18, 0x59, 0x0f, 0x06,
12334 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12335 0x43, 0xf4, 0x9f, 0xfe,
12336 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12337 0x9e, 0xfe, 0xf3, 0x10,
12338 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12339 0x17, 0xfe, 0x4d, 0xe4,
12340 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12341 0x17, 0xfe, 0x4d, 0xe4,
12342 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12343 0xf4, 0x00, 0xe9, 0x91,
12344 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12345 0x04, 0x16, 0x06, 0x01,
12346 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12347 0x0b, 0x26, 0xf3, 0x76,
12348 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12349 0x16, 0x19, 0x01, 0x0b,
12350 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12351 0x0b, 0x26, 0xb1, 0x76,
12352 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12353 0xfe, 0x48, 0x13, 0xb8,
12354 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12355 0xec, 0xfe, 0x27, 0x01,
12356 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12357 0x07, 0xfe, 0xe3, 0x00,
12358 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12359 0x22, 0xd4, 0x07, 0x06,
12360 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12361 0x07, 0x11, 0xae, 0x09,
12362 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12363 0x0e, 0x8e, 0xfe, 0x80,
12364 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12365 0x09, 0x48, 0x01, 0x0e,
12366 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12367 0x80, 0xfe, 0x80, 0x4c,
12368 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12369 0x09, 0x5d, 0x01, 0x87,
12370 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12371 0x19, 0xde, 0xfe, 0x24,
12372 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12373 0x17, 0xad, 0x9a, 0x1b,
12374 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12375 0x16, 0xfe, 0xda, 0x10,
12376 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12377 0x18, 0x58, 0x03, 0xfe,
12378 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12379 0xf4, 0x06, 0xfe, 0x3c,
12380 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12381 0x97, 0xfe, 0x38, 0x17,
12382 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12383 0x10, 0x18, 0x11, 0x75,
12384 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12385 0x2e, 0x97, 0xfe, 0x5a,
12386 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12387 0xfe, 0x98, 0xe7, 0x00,
12388 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12389 0xfe, 0x30, 0xbc, 0xfe,
12390 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12391 0xcb, 0x97, 0xfe, 0x92,
12392 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12393 0x42, 0x10, 0xfe, 0x02,
12394 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12395 0x03, 0xa1, 0xfe, 0x1d,
12396 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12397 0x9a, 0x5b, 0x41, 0xfe,
12398 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12399 0x11, 0x12, 0xfe, 0xdd,
12400 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12401 0x17, 0x15, 0x06, 0x39,
12402 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12403 0xfe, 0x7e, 0x18, 0x1e,
12404 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12405 0x12, 0xfe, 0xe1, 0x10,
12406 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12407 0x13, 0x42, 0x92, 0x09,
12408 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12409 0xf0, 0xfe, 0x00, 0xcc,
12410 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12411 0x0e, 0xfe, 0x80, 0x4c,
12412 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12413 0x24, 0x12, 0xfe, 0x14,
12414 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12415 0xe7, 0x0a, 0x10, 0xfe,
12416 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12417 0x08, 0x54, 0x1b, 0x37,
12418 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12419 0x90, 0x3a, 0xce, 0x3b,
12420 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
12421 0x13, 0xa3, 0x04, 0x09,
12422 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
12423 0x44, 0x17, 0xfe, 0xe8,
12424 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
12425 0x5d, 0x01, 0xa8, 0x09,
12426 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
12427 0x1c, 0x19, 0x03, 0xfe,
12428 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
12429 0x6b, 0xfe, 0x2e, 0x19,
12430 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
12431 0xfe, 0x0b, 0x00, 0x6b,
12432 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
12433 0x08, 0x10, 0x03, 0xfe,
12434 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
12435 0x04, 0x68, 0x54, 0xe7,
12436 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
12437 0x1a, 0xf4, 0xfe, 0x00,
12438 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
12439 0x04, 0x07, 0x7e, 0xfe,
12440 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12441 0x07, 0x1a, 0xfe, 0x5a,
12442 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
12443 0x25, 0x6d, 0xe5, 0x07,
12444 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
12445 0xa9, 0xb8, 0x04, 0x15,
12446 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
12447 0x40, 0x5c, 0x04, 0x1c,
12448 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
12449 0xf7, 0xfe, 0x82, 0xf0,
12450 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012451};
12452
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012453static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
12454static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012455
12456/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012457static unsigned char _adv_asc38C1600_buf[] = {
12458 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
12459 0x18, 0xe4, 0x01, 0x00,
12460 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
12461 0x07, 0x17, 0xc0, 0x5f,
12462 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
12463 0x85, 0xf0, 0x86, 0xf0,
12464 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
12465 0x98, 0x57, 0x01, 0xe6,
12466 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
12467 0x38, 0x54, 0x32, 0xf0,
12468 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
12469 0x00, 0xe6, 0xb1, 0xf0,
12470 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
12471 0x06, 0x13, 0x0c, 0x1c,
12472 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
12473 0xb9, 0x54, 0x00, 0x80,
12474 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
12475 0x03, 0xe6, 0x01, 0xea,
12476 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
12477 0x04, 0x13, 0xbb, 0x55,
12478 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
12479 0xbb, 0x00, 0xc0, 0x00,
12480 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
12481 0x4c, 0x1c, 0x4e, 0x1c,
12482 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
12483 0x24, 0x01, 0x3c, 0x01,
12484 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
12485 0x78, 0x01, 0x7c, 0x01,
12486 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
12487 0x6e, 0x1e, 0x02, 0x48,
12488 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
12489 0x03, 0xfc, 0x06, 0x00,
12490 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
12491 0x30, 0x1c, 0x38, 0x1c,
12492 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
12493 0x5d, 0xf0, 0xa7, 0xf0,
12494 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
12495 0x33, 0x00, 0x34, 0x00,
12496 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
12497 0x79, 0x01, 0x3c, 0x09,
12498 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
12499 0x40, 0x16, 0x50, 0x16,
12500 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
12501 0x05, 0xf0, 0x09, 0xf0,
12502 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
12503 0x9c, 0x00, 0xa4, 0x00,
12504 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
12505 0xe9, 0x09, 0x5c, 0x0c,
12506 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
12507 0x42, 0x1d, 0x08, 0x44,
12508 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
12509 0x83, 0x55, 0x83, 0x59,
12510 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
12511 0x4b, 0xf4, 0x04, 0xf8,
12512 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
12513 0xa8, 0x00, 0xaa, 0x00,
12514 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
12515 0x7a, 0x01, 0x82, 0x01,
12516 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
12517 0x68, 0x08, 0x10, 0x0d,
12518 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
12519 0xf3, 0x10, 0x06, 0x12,
12520 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
12521 0xf0, 0x35, 0x05, 0xfe,
12522 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
12523 0xfe, 0x88, 0x01, 0xff,
12524 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12525 0x00, 0xfe, 0x57, 0x24,
12526 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
12527 0x00, 0x00, 0xff, 0x08,
12528 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12529 0xff, 0xff, 0xff, 0x13,
12530 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12531 0xfe, 0x04, 0xf7, 0xe8,
12532 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
12533 0x0d, 0x51, 0x37, 0xfe,
12534 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
12535 0xfe, 0xf8, 0x01, 0xfe,
12536 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
12537 0x05, 0xfe, 0x08, 0x0f,
12538 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
12539 0x28, 0x1c, 0x03, 0xfe,
12540 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
12541 0x48, 0xf0, 0xfe, 0x90,
12542 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
12543 0x02, 0xfe, 0x46, 0xf0,
12544 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
12545 0xfe, 0x4e, 0x02, 0xfe,
12546 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
12547 0x0d, 0xa2, 0x1c, 0x07,
12548 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
12549 0x1c, 0xf5, 0xfe, 0x1e,
12550 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
12551 0xde, 0x0a, 0x81, 0x01,
12552 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
12553 0x81, 0x01, 0x5c, 0xfe,
12554 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
12555 0xfe, 0x58, 0x1c, 0x1c,
12556 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
12557 0x2b, 0xfe, 0x9e, 0x02,
12558 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
12559 0x00, 0x47, 0xb8, 0x01,
12560 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
12561 0x1a, 0x31, 0xfe, 0x69,
12562 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
12563 0x1e, 0x1e, 0x20, 0x2c,
12564 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
12565 0x44, 0x15, 0x56, 0x51,
12566 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
12567 0x01, 0x18, 0x09, 0x00,
12568 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
12569 0x18, 0xfe, 0xc8, 0x54,
12570 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
12571 0xfe, 0x02, 0xe8, 0x30,
12572 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
12573 0xfe, 0xe4, 0x01, 0xfe,
12574 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
12575 0x26, 0xf0, 0xfe, 0x66,
12576 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
12577 0xef, 0x10, 0xfe, 0x9f,
12578 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
12579 0x70, 0x37, 0xfe, 0x48,
12580 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
12581 0x21, 0xb9, 0xc7, 0x20,
12582 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
12583 0xe1, 0x2a, 0xeb, 0xfe,
12584 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
12585 0x15, 0xfe, 0xe4, 0x00,
12586 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
12587 0xfe, 0x06, 0xf0, 0xfe,
12588 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
12589 0x03, 0x81, 0x1e, 0x1b,
12590 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
12591 0xea, 0xfe, 0x46, 0x1c,
12592 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12593 0xfe, 0x48, 0x1c, 0x75,
12594 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
12595 0xe1, 0x01, 0x18, 0x77,
12596 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
12597 0x8f, 0xfe, 0x70, 0x02,
12598 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
12599 0x16, 0xfe, 0x4a, 0x04,
12600 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
12601 0x02, 0x00, 0x10, 0x01,
12602 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
12603 0xee, 0xfe, 0x4c, 0x44,
12604 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
12605 0x7b, 0xec, 0x60, 0x8d,
12606 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
12607 0x0c, 0x06, 0x28, 0xfe,
12608 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
12609 0x13, 0x34, 0xfe, 0x4c,
12610 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
12611 0x13, 0x01, 0x0c, 0x06,
12612 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
12613 0x28, 0xf9, 0x1f, 0x7f,
12614 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
12615 0xfe, 0xa4, 0x0e, 0x05,
12616 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
12617 0x9c, 0x93, 0x3a, 0x0b,
12618 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
12619 0x7d, 0x1d, 0xfe, 0x46,
12620 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
12621 0xfe, 0x87, 0x83, 0xfe,
12622 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
12623 0x13, 0x0f, 0xfe, 0x20,
12624 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
12625 0x12, 0x01, 0x38, 0x06,
12626 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
12627 0x05, 0xd0, 0x54, 0x01,
12628 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
12629 0x50, 0x12, 0x5e, 0xff,
12630 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
12631 0x00, 0x10, 0x2f, 0xfe,
12632 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
12633 0x38, 0xfe, 0x4a, 0xf0,
12634 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
12635 0x21, 0x00, 0xf1, 0x2e,
12636 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
12637 0x10, 0x2f, 0xfe, 0xd0,
12638 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
12639 0x1c, 0x00, 0x4d, 0x01,
12640 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
12641 0x28, 0xfe, 0x24, 0x12,
12642 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
12643 0x0d, 0x00, 0x01, 0x42,
12644 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
12645 0x03, 0xb6, 0x1e, 0xfe,
12646 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
12647 0xfe, 0x72, 0x06, 0x0a,
12648 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
12649 0x19, 0x16, 0xfe, 0x68,
12650 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
12651 0x03, 0x9a, 0x1e, 0xfe,
12652 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
12653 0x48, 0xfe, 0x92, 0x06,
12654 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
12655 0x58, 0xff, 0x02, 0x00,
12656 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
12657 0xfe, 0xea, 0x06, 0x01,
12658 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
12659 0xfe, 0xe0, 0x06, 0x15,
12660 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
12661 0x01, 0x84, 0xfe, 0xae,
12662 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
12663 0x1e, 0xfe, 0x1a, 0x12,
12664 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
12665 0x43, 0x48, 0x62, 0x80,
12666 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
12667 0x36, 0xfe, 0x02, 0xf6,
12668 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
12669 0xd0, 0x0d, 0x17, 0xfe,
12670 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
12671 0x9e, 0x15, 0x82, 0x01,
12672 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
12673 0x57, 0x10, 0xe6, 0x05,
12674 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
12675 0xfe, 0x9c, 0x32, 0x5f,
12676 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
12677 0xfe, 0x0a, 0xf0, 0xfe,
12678 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
12679 0xaf, 0xa0, 0x05, 0x29,
12680 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
12681 0x00, 0x01, 0x08, 0x14,
12682 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
12683 0x14, 0x00, 0x05, 0xfe,
12684 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
12685 0x12, 0xfe, 0x30, 0x13,
12686 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
12687 0x01, 0x08, 0x14, 0x00,
12688 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
12689 0x78, 0x4f, 0x0f, 0xfe,
12690 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
12691 0x28, 0x48, 0xfe, 0x6c,
12692 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
12693 0x12, 0x53, 0x63, 0x4e,
12694 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
12695 0x6c, 0x08, 0xaf, 0xa0,
12696 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
12697 0x05, 0xed, 0xfe, 0x9c,
12698 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
12699 0x1e, 0xfe, 0x99, 0x58,
12700 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
12701 0x22, 0x6b, 0x01, 0x0c,
12702 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
12703 0x1e, 0x47, 0x2c, 0x7a,
12704 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
12705 0x01, 0x0c, 0x61, 0x65,
12706 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
12707 0x16, 0xfe, 0x08, 0x50,
12708 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
12709 0x01, 0xfe, 0xce, 0x1e,
12710 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
12711 0x01, 0xfe, 0xfe, 0x1e,
12712 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
12713 0x10, 0x01, 0x0c, 0x06,
12714 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
12715 0x10, 0x6a, 0x22, 0x6b,
12716 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
12717 0xfe, 0x9f, 0x83, 0x33,
12718 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
12719 0x3a, 0x0b, 0xfe, 0xc6,
12720 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
12721 0x01, 0xfe, 0xce, 0x1e,
12722 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
12723 0x04, 0xfe, 0xc0, 0x93,
12724 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
12725 0x10, 0x4b, 0x22, 0x4c,
12726 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
12727 0x4e, 0x11, 0x2f, 0xfe,
12728 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
12729 0x3c, 0x37, 0x88, 0xf5,
12730 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
12731 0xd3, 0xfe, 0x42, 0x0a,
12732 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
12733 0x05, 0x29, 0x01, 0x41,
12734 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
12735 0xfe, 0x14, 0x12, 0x01,
12736 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
12737 0x2e, 0x1c, 0x05, 0xfe,
12738 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
12739 0xfe, 0x2c, 0x1c, 0xfe,
12740 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
12741 0x92, 0x10, 0xc4, 0xf6,
12742 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
12743 0xe7, 0x10, 0xfe, 0x2b,
12744 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
12745 0xac, 0xfe, 0xd2, 0xf0,
12746 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
12747 0x1b, 0xbf, 0xd4, 0x5b,
12748 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
12749 0x5e, 0x32, 0x1f, 0x7f,
12750 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
12751 0x05, 0x70, 0xfe, 0x74,
12752 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
12753 0x0f, 0x4d, 0x01, 0xfe,
12754 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
12755 0x0d, 0x2b, 0xfe, 0xe2,
12756 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
12757 0xfe, 0x88, 0x13, 0x21,
12758 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
12759 0x83, 0x83, 0xfe, 0xc9,
12760 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
12761 0x91, 0x04, 0xfe, 0x84,
12762 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
12763 0xfe, 0xcb, 0x57, 0x0b,
12764 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
12765 0x6a, 0x3b, 0x6b, 0x10,
12766 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
12767 0x20, 0x6e, 0xdb, 0x64,
12768 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
12769 0xfe, 0x04, 0xfa, 0x64,
12770 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
12771 0x10, 0x98, 0x91, 0x6c,
12772 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
12773 0x4b, 0x7e, 0x4c, 0x01,
12774 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
12775 0x58, 0xfe, 0x91, 0x58,
12776 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
12777 0x1b, 0x40, 0x01, 0x0c,
12778 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
12779 0xfe, 0x10, 0x90, 0x04,
12780 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
12781 0x79, 0x0b, 0x0e, 0xfe,
12782 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
12783 0x01, 0x0c, 0x06, 0x0d,
12784 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
12785 0x0c, 0x58, 0xfe, 0x8d,
12786 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
12787 0x83, 0x33, 0x0b, 0x0e,
12788 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
12789 0x19, 0xfe, 0x19, 0x41,
12790 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
12791 0x19, 0xfe, 0x44, 0x00,
12792 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
12793 0x4c, 0xfe, 0x0c, 0x51,
12794 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
12795 0x76, 0x10, 0xac, 0xfe,
12796 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
12797 0xe3, 0x23, 0x07, 0xfe,
12798 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
12799 0xcc, 0x0c, 0x1f, 0x92,
12800 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
12801 0x0c, 0xfe, 0x3e, 0x10,
12802 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
12803 0xfe, 0xcb, 0xf0, 0xfe,
12804 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
12805 0xf4, 0x0c, 0x19, 0x94,
12806 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
12807 0xfe, 0xcc, 0xf0, 0xef,
12808 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
12809 0x4e, 0x11, 0x2f, 0xfe,
12810 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
12811 0x3c, 0x37, 0x88, 0xf5,
12812 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
12813 0x2f, 0xfe, 0x3e, 0x0d,
12814 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
12815 0xd2, 0x9f, 0xd3, 0x9f,
12816 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
12817 0xc5, 0x75, 0xd7, 0x99,
12818 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
12819 0x9c, 0x2f, 0xfe, 0x8c,
12820 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
12821 0x42, 0x00, 0x05, 0x70,
12822 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
12823 0x0d, 0xfe, 0x44, 0x13,
12824 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
12825 0xfe, 0xda, 0x0e, 0x0a,
12826 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
12827 0x10, 0x01, 0xfe, 0xf4,
12828 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
12829 0x15, 0x56, 0x01, 0x85,
12830 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
12831 0xcc, 0x10, 0x01, 0xa7,
12832 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
12833 0xfe, 0x99, 0x83, 0xfe,
12834 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
12835 0x43, 0x00, 0xfe, 0xa2,
12836 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
12837 0x00, 0x1d, 0x40, 0x15,
12838 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
12839 0xfe, 0x3a, 0x03, 0x01,
12840 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
12841 0x76, 0x06, 0x12, 0xfe,
12842 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
12843 0xfe, 0x9d, 0xf0, 0xfe,
12844 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
12845 0x0c, 0x61, 0x12, 0x44,
12846 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
12847 0xfe, 0x2e, 0x10, 0x19,
12848 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
12849 0xfe, 0x41, 0x00, 0xa2,
12850 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
12851 0xea, 0x4f, 0xfe, 0x04,
12852 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
12853 0x35, 0xfe, 0x12, 0x1c,
12854 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
12855 0xfe, 0xd4, 0x11, 0x05,
12856 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
12857 0xce, 0x45, 0x31, 0x51,
12858 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
12859 0x67, 0xfe, 0x98, 0x56,
12860 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
12861 0x0c, 0x06, 0x28, 0xfe,
12862 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
12863 0xfe, 0xfa, 0x14, 0xfe,
12864 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
12865 0xfe, 0xe0, 0x14, 0xfe,
12866 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
12867 0xfe, 0xad, 0x13, 0x05,
12868 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
12869 0xe7, 0xfe, 0x08, 0x1c,
12870 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
12871 0x48, 0x55, 0xa5, 0x3b,
12872 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
12873 0xf0, 0x1a, 0x03, 0xfe,
12874 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
12875 0xec, 0xe7, 0x53, 0x00,
12876 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
12877 0x01, 0xfe, 0x62, 0x1b,
12878 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
12879 0xea, 0xe7, 0x53, 0x92,
12880 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
12881 0xfe, 0x38, 0x01, 0x23,
12882 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
12883 0x01, 0x01, 0xfe, 0x1e,
12884 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
12885 0x26, 0x02, 0x21, 0x96,
12886 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
12887 0xc3, 0xfe, 0xe1, 0x10,
12888 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
12889 0xfe, 0x03, 0xdc, 0xfe,
12890 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
12891 0x00, 0xcc, 0x02, 0xfe,
12892 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
12893 0x0f, 0xfe, 0x1c, 0x80,
12894 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
12895 0x0f, 0xfe, 0x1e, 0x80,
12896 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
12897 0x1d, 0x80, 0x04, 0xfe,
12898 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
12899 0x1e, 0xac, 0xfe, 0x14,
12900 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
12901 0x1f, 0xfe, 0x30, 0xf4,
12902 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
12903 0x56, 0xfb, 0x01, 0xfe,
12904 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
12905 0xfe, 0x00, 0x1d, 0x15,
12906 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
12907 0x22, 0x1b, 0xfe, 0x1e,
12908 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
12909 0x96, 0x90, 0x04, 0xfe,
12910 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
12911 0x01, 0x01, 0x0c, 0x06,
12912 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
12913 0x0e, 0x77, 0xfe, 0x01,
12914 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
12915 0x21, 0x2c, 0xfe, 0x00,
12916 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
12917 0x06, 0x58, 0x03, 0xfe,
12918 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
12919 0x03, 0xfe, 0xb2, 0x00,
12920 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
12921 0x66, 0x10, 0x55, 0x10,
12922 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
12923 0x54, 0x2b, 0xfe, 0x88,
12924 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
12925 0x91, 0x54, 0x2b, 0xfe,
12926 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
12927 0x00, 0x40, 0x8d, 0x2c,
12928 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
12929 0x12, 0x1c, 0x75, 0xfe,
12930 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
12931 0x14, 0xfe, 0x0e, 0x47,
12932 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
12933 0xa7, 0x90, 0x34, 0x60,
12934 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
12935 0x09, 0x56, 0xfe, 0x34,
12936 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
12937 0xfe, 0x45, 0x48, 0x01,
12938 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
12939 0x09, 0x1a, 0xa5, 0x0a,
12940 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
12941 0xfe, 0x14, 0x56, 0xfe,
12942 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
12943 0xec, 0xb8, 0xfe, 0x9e,
12944 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
12945 0xf4, 0xfe, 0xdd, 0x10,
12946 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
12947 0x12, 0x09, 0x0d, 0xfe,
12948 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
12949 0x13, 0x09, 0xfe, 0x23,
12950 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
12951 0x24, 0xfe, 0x12, 0x12,
12952 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
12953 0xae, 0x41, 0x02, 0x32,
12954 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
12955 0x35, 0x32, 0x01, 0x43,
12956 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
12957 0x13, 0x01, 0x0c, 0x06,
12958 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
12959 0xe5, 0x55, 0xb0, 0xfe,
12960 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
12961 0xfe, 0xb6, 0x0e, 0x10,
12962 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
12963 0x88, 0x20, 0x6e, 0x01,
12964 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
12965 0x55, 0xfe, 0x04, 0xfa,
12966 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
12967 0xfe, 0x40, 0x56, 0xfe,
12968 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
12969 0x44, 0x55, 0xfe, 0xe5,
12970 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
12971 0x68, 0x22, 0x69, 0x01,
12972 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
12973 0x6b, 0xfe, 0x2c, 0x50,
12974 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
12975 0x50, 0x03, 0x68, 0x3b,
12976 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
12977 0x40, 0x50, 0xfe, 0xc2,
12978 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
12979 0x16, 0x3d, 0x27, 0x25,
12980 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
12981 0xa6, 0x23, 0x3f, 0x1b,
12982 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
12983 0xfe, 0x0a, 0x55, 0x31,
12984 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
12985 0x51, 0x05, 0x72, 0x01,
12986 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
12987 0x2a, 0x3c, 0x16, 0xc0,
12988 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
12989 0xfe, 0x66, 0x15, 0x05,
12990 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
12991 0x2b, 0x3d, 0x01, 0x08,
12992 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
12993 0xb6, 0x1e, 0x83, 0x01,
12994 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
12995 0x07, 0x90, 0x3f, 0x01,
12996 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
12997 0x01, 0x43, 0x09, 0x82,
12998 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
12999 0x05, 0x72, 0xfe, 0xc0,
13000 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
13001 0x32, 0x01, 0x08, 0x17,
13002 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
13003 0x3d, 0x27, 0x25, 0xbd,
13004 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
13005 0xe8, 0x14, 0x01, 0xa6,
13006 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
13007 0x0e, 0x12, 0x01, 0x43,
13008 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
13009 0x01, 0x08, 0x17, 0x73,
13010 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
13011 0x27, 0x25, 0xbd, 0x09,
13012 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
13013 0xb6, 0x14, 0x86, 0xa8,
13014 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
13015 0x82, 0x4e, 0x05, 0x72,
13016 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
13017 0xfe, 0xc0, 0x19, 0x05,
13018 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
13019 0xcc, 0x01, 0x08, 0x26,
13020 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
13021 0xcc, 0x15, 0x5e, 0x32,
13022 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
13023 0xad, 0x23, 0xfe, 0xff,
13024 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
13025 0x00, 0x57, 0x52, 0xad,
13026 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
13027 0x02, 0x00, 0x57, 0x52,
13028 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
13029 0x02, 0x13, 0x58, 0xff,
13030 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
13031 0x5c, 0x0a, 0x55, 0x01,
13032 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
13033 0xff, 0x03, 0x00, 0x54,
13034 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
13035 0x7c, 0x3a, 0x0b, 0x0e,
13036 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
13037 0xfe, 0x1a, 0xf7, 0x00,
13038 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
13039 0xda, 0x6d, 0x02, 0xfe,
13040 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
13041 0x02, 0x01, 0xc6, 0xfe,
13042 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
13043 0x25, 0xbe, 0x01, 0x08,
13044 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
13045 0x03, 0x9a, 0x1e, 0xfe,
13046 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
13047 0x48, 0xfe, 0x08, 0x17,
13048 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
13049 0x17, 0x4d, 0x13, 0x07,
13050 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
13051 0xff, 0x02, 0x83, 0x55,
13052 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
13053 0x17, 0x1c, 0x63, 0x13,
13054 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
13055 0x00, 0xb0, 0xfe, 0x80,
13056 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
13057 0x53, 0x07, 0xfe, 0x60,
13058 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
13059 0x00, 0x1c, 0x95, 0x13,
13060 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
13061 0xfe, 0x43, 0xf4, 0x96,
13062 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
13063 0xf4, 0x94, 0xf6, 0x8b,
13064 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
13065 0xda, 0x17, 0x62, 0x49,
13066 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
13067 0x71, 0x50, 0x26, 0xfe,
13068 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
13069 0x58, 0x02, 0x50, 0x13,
13070 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
13071 0x25, 0xbe, 0xfe, 0x03,
13072 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
13073 0x0a, 0x01, 0x08, 0x16,
13074 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13075 0x01, 0x08, 0x16, 0xa9,
13076 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13077 0x08, 0x16, 0xa9, 0x27,
13078 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13079 0x01, 0x38, 0x06, 0x24,
13080 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13081 0x78, 0x03, 0x9a, 0x1e,
13082 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13083 0xfe, 0x40, 0x5a, 0x23,
13084 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13085 0x80, 0x48, 0xfe, 0xaa,
13086 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13087 0xfe, 0xac, 0x1d, 0xfe,
13088 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13089 0x43, 0x48, 0x2d, 0x93,
13090 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13091 0x36, 0xfe, 0x34, 0xf4,
13092 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13093 0x28, 0x10, 0xfe, 0xc0,
13094 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13095 0x18, 0x45, 0xfe, 0x1c,
13096 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13097 0x19, 0xfe, 0x04, 0xf4,
13098 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13099 0x21, 0xfe, 0x7f, 0x01,
13100 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13101 0x7e, 0x01, 0xfe, 0xc8,
13102 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13103 0x21, 0xfe, 0x81, 0x01,
13104 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13105 0x13, 0x0d, 0x02, 0x14,
13106 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13107 0xfe, 0x82, 0x19, 0x14,
13108 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13109 0x08, 0x02, 0x14, 0x07,
13110 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13111 0x01, 0x08, 0x17, 0xc1,
13112 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13113 0x08, 0x02, 0x50, 0x02,
13114 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13115 0x14, 0x12, 0x01, 0x08,
13116 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13117 0x08, 0x17, 0x74, 0xfe,
13118 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13119 0x74, 0x5f, 0xcc, 0x01,
13120 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13121 0xfe, 0x49, 0xf4, 0x00,
13122 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13123 0x02, 0x00, 0x10, 0x2f,
13124 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13125 0x16, 0xfe, 0x64, 0x1a,
13126 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13127 0x61, 0x07, 0x44, 0x02,
13128 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13129 0x13, 0x0a, 0x9d, 0x01,
13130 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13131 0xfe, 0x80, 0xe7, 0x1a,
13132 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13133 0x0a, 0x5a, 0x01, 0x18,
13134 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13135 0x7e, 0x1e, 0xfe, 0x80,
13136 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13137 0xfe, 0x80, 0x4c, 0x0a,
13138 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13139 0xfe, 0x19, 0xde, 0xfe,
13140 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13141 0x2a, 0x1c, 0xfa, 0xb3,
13142 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13143 0xf4, 0x1a, 0xfe, 0xfa,
13144 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13145 0xfe, 0x18, 0x58, 0x03,
13146 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13147 0xfe, 0x30, 0xf4, 0x07,
13148 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13149 0xf7, 0x24, 0xb1, 0xfe,
13150 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13151 0xfe, 0xba, 0x10, 0x1c,
13152 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13153 0x1d, 0xf7, 0x54, 0xb1,
13154 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13155 0xaf, 0x19, 0xfe, 0x98,
13156 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13157 0x1a, 0x87, 0x8b, 0x0f,
13158 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13159 0xfe, 0x32, 0x90, 0x04,
13160 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13161 0x7c, 0x12, 0xfe, 0x0f,
13162 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13163 0x31, 0x02, 0xc9, 0x2b,
13164 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13165 0x6a, 0xfe, 0x19, 0xfe,
13166 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13167 0x1b, 0xfe, 0x36, 0x14,
13168 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13169 0xfe, 0x80, 0xe7, 0x1a,
13170 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13171 0x30, 0xfe, 0x12, 0x45,
13172 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13173 0x39, 0xf0, 0x75, 0x26,
13174 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13175 0xe3, 0x23, 0x07, 0xfe,
13176 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13177 0x56, 0xfe, 0x3c, 0x13,
13178 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13179 0x01, 0x18, 0xcb, 0xfe,
13180 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13181 0xfe, 0x00, 0xcc, 0xcb,
13182 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13183 0xfe, 0x80, 0x4c, 0x01,
13184 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13185 0x12, 0xfe, 0x14, 0x56,
13186 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13187 0x0d, 0x19, 0xfe, 0x15,
13188 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13189 0x83, 0xfe, 0x18, 0x80,
13190 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13191 0x90, 0xfe, 0xba, 0x90,
13192 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13193 0x21, 0xb9, 0x88, 0x20,
13194 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13195 0x18, 0xfe, 0x49, 0x44,
13196 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13197 0x1a, 0xa4, 0x0a, 0x67,
13198 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13199 0x1d, 0x7b, 0xfe, 0x52,
13200 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13201 0x4e, 0xe4, 0xdd, 0x7b,
13202 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13203 0xfe, 0x4e, 0xe4, 0xfe,
13204 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13205 0xfe, 0x08, 0x10, 0x03,
13206 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13207 0x68, 0x54, 0xfe, 0xf1,
13208 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13209 0xfe, 0x1a, 0xf4, 0xfe,
13210 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13211 0x09, 0x92, 0xfe, 0x5a,
13212 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13213 0x5a, 0xf0, 0xfe, 0xc8,
13214 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13215 0x1a, 0x10, 0x09, 0x0d,
13216 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13217 0x1f, 0x93, 0x01, 0x42,
13218 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13219 0xfe, 0x14, 0xf0, 0x08,
13220 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13221 0xfe, 0x82, 0xf0, 0xfe,
13222 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13223 0x02, 0x0f, 0xfe, 0x18,
13224 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13225 0x80, 0x04, 0xfe, 0x82,
13226 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13227 0x83, 0x33, 0x0b, 0x0e,
13228 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13229 0x02, 0x0f, 0xfe, 0x04,
13230 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13231 0x80, 0x04, 0xfe, 0x80,
13232 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13233 0xfe, 0x99, 0x83, 0xfe,
13234 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13235 0x83, 0xfe, 0xce, 0x47,
13236 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13237 0x0b, 0x0e, 0x02, 0x0f,
13238 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13239 0xfe, 0x08, 0x90, 0x04,
13240 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13241 0xfe, 0x8a, 0x93, 0x79,
13242 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13243 0x0b, 0x0e, 0x02, 0x0f,
13244 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13245 0xfe, 0x3c, 0x90, 0x04,
13246 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13247 0x04, 0xfe, 0x83, 0x83,
13248 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013249};
13250
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013251static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13252static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013253
13254/* a_init.c */
13255/*
13256 * EEPROM Configuration.
13257 *
13258 * All drivers should use this structure to set the default EEPROM
13259 * configuration. The BIOS now uses this structure when it is built.
13260 * Additional structure information can be found in a_condor.h where
13261 * the structure is defined.
13262 *
13263 * The *_Field_IsChar structs are needed to correct for endianness.
13264 * These values are read from the board 16 bits at a time directly
13265 * into the structs. Because some fields are char, the values will be
13266 * in the wrong order. The *_Field_IsChar tells when to flip the
13267 * bytes. Data read and written to PCI memory is automatically swapped
13268 * on big-endian platforms so char fields read as words are actually being
13269 * unswapped on big-endian platforms.
13270 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013271static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013272 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13273 0x0000, /* cfg_msw */
13274 0xFFFF, /* disc_enable */
13275 0xFFFF, /* wdtr_able */
13276 0xFFFF, /* sdtr_able */
13277 0xFFFF, /* start_motor */
13278 0xFFFF, /* tagqng_able */
13279 0xFFFF, /* bios_scan */
13280 0, /* scam_tolerant */
13281 7, /* adapter_scsi_id */
13282 0, /* bios_boot_delay */
13283 3, /* scsi_reset_delay */
13284 0, /* bios_id_lun */
13285 0, /* termination */
13286 0, /* reserved1 */
13287 0xFFE7, /* bios_ctrl */
13288 0xFFFF, /* ultra_able */
13289 0, /* reserved2 */
13290 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13291 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13292 0, /* dvc_cntl */
13293 0, /* bug_fix */
13294 0, /* serial_number_word1 */
13295 0, /* serial_number_word2 */
13296 0, /* serial_number_word3 */
13297 0, /* check_sum */
13298 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13299 , /* oem_name[16] */
13300 0, /* dvc_err_code */
13301 0, /* adv_err_code */
13302 0, /* adv_err_addr */
13303 0, /* saved_dvc_err_code */
13304 0, /* saved_adv_err_code */
13305 0, /* saved_adv_err_addr */
13306 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013307};
13308
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013309static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013310 0, /* cfg_lsw */
13311 0, /* cfg_msw */
13312 0, /* -disc_enable */
13313 0, /* wdtr_able */
13314 0, /* sdtr_able */
13315 0, /* start_motor */
13316 0, /* tagqng_able */
13317 0, /* bios_scan */
13318 0, /* scam_tolerant */
13319 1, /* adapter_scsi_id */
13320 1, /* bios_boot_delay */
13321 1, /* scsi_reset_delay */
13322 1, /* bios_id_lun */
13323 1, /* termination */
13324 1, /* reserved1 */
13325 0, /* bios_ctrl */
13326 0, /* ultra_able */
13327 0, /* reserved2 */
13328 1, /* max_host_qng */
13329 1, /* max_dvc_qng */
13330 0, /* dvc_cntl */
13331 0, /* bug_fix */
13332 0, /* serial_number_word1 */
13333 0, /* serial_number_word2 */
13334 0, /* serial_number_word3 */
13335 0, /* check_sum */
13336 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13337 , /* oem_name[16] */
13338 0, /* dvc_err_code */
13339 0, /* adv_err_code */
13340 0, /* adv_err_addr */
13341 0, /* saved_dvc_err_code */
13342 0, /* saved_adv_err_code */
13343 0, /* saved_adv_err_addr */
13344 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013345};
13346
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013347static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013348 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13349 0x0000, /* 01 cfg_msw */
13350 0xFFFF, /* 02 disc_enable */
13351 0xFFFF, /* 03 wdtr_able */
13352 0x4444, /* 04 sdtr_speed1 */
13353 0xFFFF, /* 05 start_motor */
13354 0xFFFF, /* 06 tagqng_able */
13355 0xFFFF, /* 07 bios_scan */
13356 0, /* 08 scam_tolerant */
13357 7, /* 09 adapter_scsi_id */
13358 0, /* bios_boot_delay */
13359 3, /* 10 scsi_reset_delay */
13360 0, /* bios_id_lun */
13361 0, /* 11 termination_se */
13362 0, /* termination_lvd */
13363 0xFFE7, /* 12 bios_ctrl */
13364 0x4444, /* 13 sdtr_speed2 */
13365 0x4444, /* 14 sdtr_speed3 */
13366 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13367 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13368 0, /* 16 dvc_cntl */
13369 0x4444, /* 17 sdtr_speed4 */
13370 0, /* 18 serial_number_word1 */
13371 0, /* 19 serial_number_word2 */
13372 0, /* 20 serial_number_word3 */
13373 0, /* 21 check_sum */
13374 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13375 , /* 22-29 oem_name[16] */
13376 0, /* 30 dvc_err_code */
13377 0, /* 31 adv_err_code */
13378 0, /* 32 adv_err_addr */
13379 0, /* 33 saved_dvc_err_code */
13380 0, /* 34 saved_adv_err_code */
13381 0, /* 35 saved_adv_err_addr */
13382 0, /* 36 reserved */
13383 0, /* 37 reserved */
13384 0, /* 38 reserved */
13385 0, /* 39 reserved */
13386 0, /* 40 reserved */
13387 0, /* 41 reserved */
13388 0, /* 42 reserved */
13389 0, /* 43 reserved */
13390 0, /* 44 reserved */
13391 0, /* 45 reserved */
13392 0, /* 46 reserved */
13393 0, /* 47 reserved */
13394 0, /* 48 reserved */
13395 0, /* 49 reserved */
13396 0, /* 50 reserved */
13397 0, /* 51 reserved */
13398 0, /* 52 reserved */
13399 0, /* 53 reserved */
13400 0, /* 54 reserved */
13401 0, /* 55 reserved */
13402 0, /* 56 cisptr_lsw */
13403 0, /* 57 cisprt_msw */
13404 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13405 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13406 0, /* 60 reserved */
13407 0, /* 61 reserved */
13408 0, /* 62 reserved */
13409 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013410};
13411
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013412static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013413 0, /* 00 cfg_lsw */
13414 0, /* 01 cfg_msw */
13415 0, /* 02 disc_enable */
13416 0, /* 03 wdtr_able */
13417 0, /* 04 sdtr_speed1 */
13418 0, /* 05 start_motor */
13419 0, /* 06 tagqng_able */
13420 0, /* 07 bios_scan */
13421 0, /* 08 scam_tolerant */
13422 1, /* 09 adapter_scsi_id */
13423 1, /* bios_boot_delay */
13424 1, /* 10 scsi_reset_delay */
13425 1, /* bios_id_lun */
13426 1, /* 11 termination_se */
13427 1, /* termination_lvd */
13428 0, /* 12 bios_ctrl */
13429 0, /* 13 sdtr_speed2 */
13430 0, /* 14 sdtr_speed3 */
13431 1, /* 15 max_host_qng */
13432 1, /* max_dvc_qng */
13433 0, /* 16 dvc_cntl */
13434 0, /* 17 sdtr_speed4 */
13435 0, /* 18 serial_number_word1 */
13436 0, /* 19 serial_number_word2 */
13437 0, /* 20 serial_number_word3 */
13438 0, /* 21 check_sum */
13439 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13440 , /* 22-29 oem_name[16] */
13441 0, /* 30 dvc_err_code */
13442 0, /* 31 adv_err_code */
13443 0, /* 32 adv_err_addr */
13444 0, /* 33 saved_dvc_err_code */
13445 0, /* 34 saved_adv_err_code */
13446 0, /* 35 saved_adv_err_addr */
13447 0, /* 36 reserved */
13448 0, /* 37 reserved */
13449 0, /* 38 reserved */
13450 0, /* 39 reserved */
13451 0, /* 40 reserved */
13452 0, /* 41 reserved */
13453 0, /* 42 reserved */
13454 0, /* 43 reserved */
13455 0, /* 44 reserved */
13456 0, /* 45 reserved */
13457 0, /* 46 reserved */
13458 0, /* 47 reserved */
13459 0, /* 48 reserved */
13460 0, /* 49 reserved */
13461 0, /* 50 reserved */
13462 0, /* 51 reserved */
13463 0, /* 52 reserved */
13464 0, /* 53 reserved */
13465 0, /* 54 reserved */
13466 0, /* 55 reserved */
13467 0, /* 56 cisptr_lsw */
13468 0, /* 57 cisprt_msw */
13469 0, /* 58 subsysvid */
13470 0, /* 59 subsysid */
13471 0, /* 60 reserved */
13472 0, /* 61 reserved */
13473 0, /* 62 reserved */
13474 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013475};
13476
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013477static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013478 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13479 0x0000, /* 01 cfg_msw */
13480 0xFFFF, /* 02 disc_enable */
13481 0xFFFF, /* 03 wdtr_able */
13482 0x5555, /* 04 sdtr_speed1 */
13483 0xFFFF, /* 05 start_motor */
13484 0xFFFF, /* 06 tagqng_able */
13485 0xFFFF, /* 07 bios_scan */
13486 0, /* 08 scam_tolerant */
13487 7, /* 09 adapter_scsi_id */
13488 0, /* bios_boot_delay */
13489 3, /* 10 scsi_reset_delay */
13490 0, /* bios_id_lun */
13491 0, /* 11 termination_se */
13492 0, /* termination_lvd */
13493 0xFFE7, /* 12 bios_ctrl */
13494 0x5555, /* 13 sdtr_speed2 */
13495 0x5555, /* 14 sdtr_speed3 */
13496 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13497 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13498 0, /* 16 dvc_cntl */
13499 0x5555, /* 17 sdtr_speed4 */
13500 0, /* 18 serial_number_word1 */
13501 0, /* 19 serial_number_word2 */
13502 0, /* 20 serial_number_word3 */
13503 0, /* 21 check_sum */
13504 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13505 , /* 22-29 oem_name[16] */
13506 0, /* 30 dvc_err_code */
13507 0, /* 31 adv_err_code */
13508 0, /* 32 adv_err_addr */
13509 0, /* 33 saved_dvc_err_code */
13510 0, /* 34 saved_adv_err_code */
13511 0, /* 35 saved_adv_err_addr */
13512 0, /* 36 reserved */
13513 0, /* 37 reserved */
13514 0, /* 38 reserved */
13515 0, /* 39 reserved */
13516 0, /* 40 reserved */
13517 0, /* 41 reserved */
13518 0, /* 42 reserved */
13519 0, /* 43 reserved */
13520 0, /* 44 reserved */
13521 0, /* 45 reserved */
13522 0, /* 46 reserved */
13523 0, /* 47 reserved */
13524 0, /* 48 reserved */
13525 0, /* 49 reserved */
13526 0, /* 50 reserved */
13527 0, /* 51 reserved */
13528 0, /* 52 reserved */
13529 0, /* 53 reserved */
13530 0, /* 54 reserved */
13531 0, /* 55 reserved */
13532 0, /* 56 cisptr_lsw */
13533 0, /* 57 cisprt_msw */
13534 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13535 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
13536 0, /* 60 reserved */
13537 0, /* 61 reserved */
13538 0, /* 62 reserved */
13539 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013540};
13541
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013542static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013543 0, /* 00 cfg_lsw */
13544 0, /* 01 cfg_msw */
13545 0, /* 02 disc_enable */
13546 0, /* 03 wdtr_able */
13547 0, /* 04 sdtr_speed1 */
13548 0, /* 05 start_motor */
13549 0, /* 06 tagqng_able */
13550 0, /* 07 bios_scan */
13551 0, /* 08 scam_tolerant */
13552 1, /* 09 adapter_scsi_id */
13553 1, /* bios_boot_delay */
13554 1, /* 10 scsi_reset_delay */
13555 1, /* bios_id_lun */
13556 1, /* 11 termination_se */
13557 1, /* termination_lvd */
13558 0, /* 12 bios_ctrl */
13559 0, /* 13 sdtr_speed2 */
13560 0, /* 14 sdtr_speed3 */
13561 1, /* 15 max_host_qng */
13562 1, /* max_dvc_qng */
13563 0, /* 16 dvc_cntl */
13564 0, /* 17 sdtr_speed4 */
13565 0, /* 18 serial_number_word1 */
13566 0, /* 19 serial_number_word2 */
13567 0, /* 20 serial_number_word3 */
13568 0, /* 21 check_sum */
13569 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13570 , /* 22-29 oem_name[16] */
13571 0, /* 30 dvc_err_code */
13572 0, /* 31 adv_err_code */
13573 0, /* 32 adv_err_addr */
13574 0, /* 33 saved_dvc_err_code */
13575 0, /* 34 saved_adv_err_code */
13576 0, /* 35 saved_adv_err_addr */
13577 0, /* 36 reserved */
13578 0, /* 37 reserved */
13579 0, /* 38 reserved */
13580 0, /* 39 reserved */
13581 0, /* 40 reserved */
13582 0, /* 41 reserved */
13583 0, /* 42 reserved */
13584 0, /* 43 reserved */
13585 0, /* 44 reserved */
13586 0, /* 45 reserved */
13587 0, /* 46 reserved */
13588 0, /* 47 reserved */
13589 0, /* 48 reserved */
13590 0, /* 49 reserved */
13591 0, /* 50 reserved */
13592 0, /* 51 reserved */
13593 0, /* 52 reserved */
13594 0, /* 53 reserved */
13595 0, /* 54 reserved */
13596 0, /* 55 reserved */
13597 0, /* 56 cisptr_lsw */
13598 0, /* 57 cisprt_msw */
13599 0, /* 58 subsysvid */
13600 0, /* 59 subsysid */
13601 0, /* 60 reserved */
13602 0, /* 61 reserved */
13603 0, /* 62 reserved */
13604 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013605};
13606
13607/*
13608 * Initialize the ADV_DVC_VAR structure.
13609 *
13610 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13611 *
13612 * For a non-fatal error return a warning code. If there are no warnings
13613 * then 0 is returned.
13614 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013615static int __devinit AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013616{
Matthew Wilcox9649af32007-07-26 21:51:47 -060013617 unsigned short warn_code = 0;
13618 AdvPortAddr iop_base = asc_dvc->iop_base;
13619 struct pci_dev *pdev = to_pci_dev(asc_dvc->cfg->dev);
13620 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013621 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013622
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013623 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013624
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013625 /*
13626 * Save the state of the PCI Configuration Command Register
13627 * "Parity Error Response Control" Bit. If the bit is clear (0),
13628 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
13629 * DMA parity errors.
13630 */
13631 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060013632 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
13633 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013634 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013635
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013636 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
13637 ADV_LIB_VERSION_MINOR;
13638 asc_dvc->cfg->chip_version =
13639 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013640
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013641 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
13642 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
13643 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013644
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013645 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
13646 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
13647 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013649 /*
13650 * Reset the chip to start and allow register writes.
13651 */
13652 if (AdvFindSignature(iop_base) == 0) {
13653 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
13654 return ADV_ERROR;
13655 } else {
13656 /*
13657 * The caller must set 'chip_type' to a valid setting.
13658 */
13659 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
13660 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
13661 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
13662 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13663 return ADV_ERROR;
13664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013665
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013666 /*
13667 * Reset Chip.
13668 */
13669 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13670 ADV_CTRL_REG_CMD_RESET);
13671 DvcSleepMilliSecond(100);
13672 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13673 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013674
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013675 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013676 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013677 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013678 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013679 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013680 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013681 }
13682 warn_code |= status;
13683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013684
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013685 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013686}
13687
13688/*
13689 * Initialize the ASC-3550.
13690 *
13691 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13692 *
13693 * For a non-fatal error return a warning code. If there are no warnings
13694 * then 0 is returned.
13695 *
13696 * Needed after initialization for error recovery.
13697 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013698static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013699{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013700 AdvPortAddr iop_base;
13701 ushort warn_code;
13702 ADV_DCNT sum;
13703 int begin_addr;
13704 int end_addr;
13705 ushort code_sum;
13706 int word;
13707 int j;
13708 int adv_asc3550_expanded_size;
13709 ADV_CARR_T *carrp;
13710 ADV_DCNT contig_len;
13711 ADV_SDCNT buf_size;
13712 ADV_PADDR carr_paddr;
13713 int i;
13714 ushort scsi_cfg1;
13715 uchar tid;
13716 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
13717 ushort wdtr_able = 0, sdtr_able, tagqng_able;
13718 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013720 /* If there is already an error, don't continue. */
13721 if (asc_dvc->err_code != 0) {
13722 return ADV_ERROR;
13723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013724
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013725 /*
13726 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
13727 */
13728 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
13729 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13730 return ADV_ERROR;
13731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013732
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013733 warn_code = 0;
13734 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013735
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013736 /*
13737 * Save the RISC memory BIOS region before writing the microcode.
13738 * The BIOS may already be loaded and using its RISC LRAM region
13739 * so its region must be saved and restored.
13740 *
13741 * Note: This code makes the assumption, which is currently true,
13742 * that a chip reset does not clear RISC LRAM.
13743 */
13744 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13745 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13746 bios_mem[i]);
13747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013748
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013749 /*
13750 * Save current per TID negotiated values.
13751 */
13752 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
13753 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013754
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013755 bios_version =
13756 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
13757 major = (bios_version >> 12) & 0xF;
13758 minor = (bios_version >> 8) & 0xF;
13759 if (major < 3 || (major == 3 && minor == 1)) {
13760 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
13761 AdvReadWordLram(iop_base, 0x120, wdtr_able);
13762 } else {
13763 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13764 }
13765 }
13766 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13767 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13768 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13769 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13770 max_cmd[tid]);
13771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013772
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013773 /*
13774 * Load the Microcode
13775 *
13776 * Write the microcode image to RISC memory starting at address 0.
13777 */
13778 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
13779 /* Assume the following compressed format of the microcode buffer:
13780 *
13781 * 254 word (508 byte) table indexed by byte code followed
13782 * by the following byte codes:
13783 *
13784 * 1-Byte Code:
13785 * 00: Emit word 0 in table.
13786 * 01: Emit word 1 in table.
13787 * .
13788 * FD: Emit word 253 in table.
13789 *
13790 * Multi-Byte Code:
13791 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
13792 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
13793 */
13794 word = 0;
13795 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
13796 if (_adv_asc3550_buf[i] == 0xff) {
13797 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
13798 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13799 _adv_asc3550_buf
13800 [i +
13801 3] << 8) |
13802 _adv_asc3550_buf
13803 [i + 2]));
13804 word++;
13805 }
13806 i += 3;
13807 } else if (_adv_asc3550_buf[i] == 0xfe) {
13808 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13809 _adv_asc3550_buf[i +
13810 2]
13811 << 8) |
13812 _adv_asc3550_buf[i +
13813 1]));
13814 i += 2;
13815 word++;
13816 } else {
13817 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13818 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
13819 word++;
13820 }
13821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013822
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013823 /*
13824 * Set 'word' for later use to clear the rest of memory and save
13825 * the expanded mcode size.
13826 */
13827 word *= 2;
13828 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013829
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013830 /*
13831 * Clear the rest of ASC-3550 Internal RAM (8KB).
13832 */
13833 for (; word < ADV_3550_MEMSIZE; word += 2) {
13834 AdvWriteWordAutoIncLram(iop_base, 0);
13835 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013837 /*
13838 * Verify the microcode checksum.
13839 */
13840 sum = 0;
13841 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013842
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013843 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
13844 sum += AdvReadWordAutoIncLram(iop_base);
13845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013846
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013847 if (sum != _adv_asc3550_chksum) {
13848 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
13849 return ADV_ERROR;
13850 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013851
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013852 /*
13853 * Restore the RISC memory BIOS region.
13854 */
13855 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13856 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13857 bios_mem[i]);
13858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013859
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013860 /*
13861 * Calculate and write the microcode code checksum to the microcode
13862 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
13863 */
13864 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
13865 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
13866 code_sum = 0;
13867 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
13868 for (word = begin_addr; word < end_addr; word += 2) {
13869 code_sum += AdvReadWordAutoIncLram(iop_base);
13870 }
13871 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013872
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013873 /*
13874 * Read and save microcode version and date.
13875 */
13876 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
13877 asc_dvc->cfg->mcode_date);
13878 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
13879 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013880
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013881 /*
13882 * Set the chip type to indicate the ASC3550.
13883 */
13884 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013885
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013886 /*
13887 * If the PCI Configuration Command Register "Parity Error Response
13888 * Control" Bit was clear (0), then set the microcode variable
13889 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
13890 * to ignore DMA parity errors.
13891 */
13892 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
13893 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13894 word |= CONTROL_FLAG_IGNORE_PERR;
13895 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013897
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013898 /*
13899 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
13900 * threshold of 128 bytes. This register is only accessible to the host.
13901 */
13902 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
13903 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013904
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013905 /*
13906 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040013907 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013908 * device reports it is capable of in Inquiry byte 7.
13909 *
13910 * If SCSI Bus Resets have been disabled, then directly set
13911 * SDTR and WDTR from the EEPROM configuration. This will allow
13912 * the BIOS and warm boot to work without a SCSI bus hang on
13913 * the Inquiry caused by host and target mismatched DTR values.
13914 * Without the SCSI Bus Reset, before an Inquiry a device can't
13915 * be assumed to be in Asynchronous, Narrow mode.
13916 */
13917 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
13918 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
13919 asc_dvc->wdtr_able);
13920 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
13921 asc_dvc->sdtr_able);
13922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013923
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013924 /*
13925 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
13926 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
13927 * bitmask. These values determine the maximum SDTR speed negotiated
13928 * with a device.
13929 *
13930 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
13931 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
13932 * without determining here whether the device supports SDTR.
13933 *
13934 * 4-bit speed SDTR speed name
13935 * =========== ===============
13936 * 0000b (0x0) SDTR disabled
13937 * 0001b (0x1) 5 Mhz
13938 * 0010b (0x2) 10 Mhz
13939 * 0011b (0x3) 20 Mhz (Ultra)
13940 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
13941 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
13942 * 0110b (0x6) Undefined
13943 * .
13944 * 1111b (0xF) Undefined
13945 */
13946 word = 0;
13947 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13948 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
13949 /* Set Ultra speed for TID 'tid'. */
13950 word |= (0x3 << (4 * (tid % 4)));
13951 } else {
13952 /* Set Fast speed for TID 'tid'. */
13953 word |= (0x2 << (4 * (tid % 4)));
13954 }
13955 if (tid == 3) { /* Check if done with sdtr_speed1. */
13956 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
13957 word = 0;
13958 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
13959 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
13960 word = 0;
13961 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
13962 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
13963 word = 0;
13964 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
13965 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
13966 /* End of loop. */
13967 }
13968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013969
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013970 /*
13971 * Set microcode operating variable for the disconnect per TID bitmask.
13972 */
13973 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
13974 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013975
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013976 /*
13977 * Set SCSI_CFG0 Microcode Default Value.
13978 *
13979 * The microcode will set the SCSI_CFG0 register using this value
13980 * after it is started below.
13981 */
13982 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
13983 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
13984 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013985
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013986 /*
13987 * Determine SCSI_CFG1 Microcode Default Value.
13988 *
13989 * The microcode will set the SCSI_CFG1 register using this value
13990 * after it is started below.
13991 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013992
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013993 /* Read current SCSI_CFG1 Register value. */
13994 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013995
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013996 /*
13997 * If all three connectors are in use, return an error.
13998 */
13999 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
14000 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
14001 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
14002 return ADV_ERROR;
14003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014004
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014005 /*
14006 * If the internal narrow cable is reversed all of the SCSI_CTRL
14007 * register signals will be set. Check for and return an error if
14008 * this condition is found.
14009 */
14010 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14011 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14012 return ADV_ERROR;
14013 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014014
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014015 /*
14016 * If this is a differential board and a single-ended device
14017 * is attached to one of the connectors, return an error.
14018 */
14019 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
14020 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
14021 return ADV_ERROR;
14022 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014023
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014024 /*
14025 * If automatic termination control is enabled, then set the
14026 * termination value based on a table listed in a_condor.h.
14027 *
14028 * If manual termination was specified with an EEPROM setting
14029 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
14030 * is ready to be 'ored' into SCSI_CFG1.
14031 */
14032 if (asc_dvc->cfg->termination == 0) {
14033 /*
14034 * The software always controls termination by setting TERM_CTL_SEL.
14035 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
14036 */
14037 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014038
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014039 switch (scsi_cfg1 & CABLE_DETECT) {
14040 /* TERM_CTL_H: on, TERM_CTL_L: on */
14041 case 0x3:
14042 case 0x7:
14043 case 0xB:
14044 case 0xD:
14045 case 0xE:
14046 case 0xF:
14047 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
14048 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014049
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014050 /* TERM_CTL_H: on, TERM_CTL_L: off */
14051 case 0x1:
14052 case 0x5:
14053 case 0x9:
14054 case 0xA:
14055 case 0xC:
14056 asc_dvc->cfg->termination |= TERM_CTL_H;
14057 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014058
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014059 /* TERM_CTL_H: off, TERM_CTL_L: off */
14060 case 0x2:
14061 case 0x6:
14062 break;
14063 }
14064 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014065
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014066 /*
14067 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
14068 */
14069 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014070
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014071 /*
14072 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
14073 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
14074 * referenced, because the hardware internally inverts
14075 * the Termination High and Low bits if TERM_POL is set.
14076 */
14077 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014078
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014079 /*
14080 * Set SCSI_CFG1 Microcode Default Value
14081 *
14082 * Set filter value and possibly modified termination control
14083 * bits in the Microcode SCSI_CFG1 Register Value.
14084 *
14085 * The microcode will set the SCSI_CFG1 register using this value
14086 * after it is started below.
14087 */
14088 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14089 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014090
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014091 /*
14092 * Set MEM_CFG Microcode Default Value
14093 *
14094 * The microcode will set the MEM_CFG register using this value
14095 * after it is started below.
14096 *
14097 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14098 * are defined.
14099 *
14100 * ASC-3550 has 8KB internal memory.
14101 */
14102 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14103 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014104
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014105 /*
14106 * Set SEL_MASK Microcode Default Value
14107 *
14108 * The microcode will set the SEL_MASK register using this value
14109 * after it is started below.
14110 */
14111 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14112 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014113
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014114 /*
14115 * Build carrier freelist.
14116 *
14117 * Driver must have already allocated memory and set 'carrier_buf'.
14118 */
14119 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014120
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014121 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14122 asc_dvc->carr_freelist = NULL;
14123 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14124 buf_size = ADV_CARRIER_BUFSIZE;
14125 } else {
14126 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014128
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014129 do {
14130 /*
14131 * Get physical address of the carrier 'carrp'.
14132 */
14133 contig_len = sizeof(ADV_CARR_T);
14134 carr_paddr =
14135 cpu_to_le32(DvcGetPhyAddr
14136 (asc_dvc, NULL, (uchar *)carrp,
14137 (ADV_SDCNT *)&contig_len,
14138 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014139
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014140 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014141
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014142 /*
14143 * If the current carrier is not physically contiguous, then
14144 * maybe there was a page crossing. Try the next carrier aligned
14145 * start address.
14146 */
14147 if (contig_len < sizeof(ADV_CARR_T)) {
14148 carrp++;
14149 continue;
14150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014151
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014152 carrp->carr_pa = carr_paddr;
14153 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014154
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014155 /*
14156 * Insert the carrier at the beginning of the freelist.
14157 */
14158 carrp->next_vpa =
14159 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14160 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014161
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014162 carrp++;
14163 }
14164 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014165
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014166 /*
14167 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14168 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014169
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014170 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14171 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14172 return ADV_ERROR;
14173 }
14174 asc_dvc->carr_freelist = (ADV_CARR_T *)
14175 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014176
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014177 /*
14178 * The first command issued will be placed in the stopper carrier.
14179 */
14180 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014181
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014182 /*
14183 * Set RISC ICQ physical address start value.
14184 */
14185 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014186
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014187 /*
14188 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14189 */
14190 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14191 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14192 return ADV_ERROR;
14193 }
14194 asc_dvc->carr_freelist = (ADV_CARR_T *)
14195 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014196
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014197 /*
14198 * The first command completed by the RISC will be placed in
14199 * the stopper.
14200 *
14201 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14202 * completed the RISC will set the ASC_RQ_STOPPER bit.
14203 */
14204 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014205
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014206 /*
14207 * Set RISC IRQ physical address start value.
14208 */
14209 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14210 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014212 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14213 (ADV_INTR_ENABLE_HOST_INTR |
14214 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014215
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014216 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14217 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014218
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014219 /* finally, finally, gentlemen, start your engine */
14220 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014221
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014222 /*
14223 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14224 * Resets should be performed. The RISC has to be running
14225 * to issue a SCSI Bus Reset.
14226 */
14227 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14228 /*
14229 * If the BIOS Signature is present in memory, restore the
14230 * BIOS Handshake Configuration Table and do not perform
14231 * a SCSI Bus Reset.
14232 */
14233 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14234 0x55AA) {
14235 /*
14236 * Restore per TID negotiated values.
14237 */
14238 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14239 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14240 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14241 tagqng_able);
14242 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14243 AdvWriteByteLram(iop_base,
14244 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14245 max_cmd[tid]);
14246 }
14247 } else {
14248 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14249 warn_code = ASC_WARN_BUSRESET_ERROR;
14250 }
14251 }
14252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014253
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014254 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014255}
14256
14257/*
14258 * Initialize the ASC-38C0800.
14259 *
14260 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14261 *
14262 * For a non-fatal error return a warning code. If there are no warnings
14263 * then 0 is returned.
14264 *
14265 * Needed after initialization for error recovery.
14266 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014267static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014268{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014269 AdvPortAddr iop_base;
14270 ushort warn_code;
14271 ADV_DCNT sum;
14272 int begin_addr;
14273 int end_addr;
14274 ushort code_sum;
14275 int word;
14276 int j;
14277 int adv_asc38C0800_expanded_size;
14278 ADV_CARR_T *carrp;
14279 ADV_DCNT contig_len;
14280 ADV_SDCNT buf_size;
14281 ADV_PADDR carr_paddr;
14282 int i;
14283 ushort scsi_cfg1;
14284 uchar byte;
14285 uchar tid;
14286 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14287 ushort wdtr_able, sdtr_able, tagqng_able;
14288 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014289
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014290 /* If there is already an error, don't continue. */
14291 if (asc_dvc->err_code != 0) {
14292 return ADV_ERROR;
14293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014294
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014295 /*
14296 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14297 */
14298 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14299 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14300 return ADV_ERROR;
14301 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014302
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014303 warn_code = 0;
14304 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014306 /*
14307 * Save the RISC memory BIOS region before writing the microcode.
14308 * The BIOS may already be loaded and using its RISC LRAM region
14309 * so its region must be saved and restored.
14310 *
14311 * Note: This code makes the assumption, which is currently true,
14312 * that a chip reset does not clear RISC LRAM.
14313 */
14314 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14315 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14316 bios_mem[i]);
14317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014318
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014319 /*
14320 * Save current per TID negotiated values.
14321 */
14322 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14323 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14324 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14325 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14326 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14327 max_cmd[tid]);
14328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014329
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014330 /*
14331 * RAM BIST (RAM Built-In Self Test)
14332 *
14333 * Address : I/O base + offset 0x38h register (byte).
14334 * Function: Bit 7-6(RW) : RAM mode
14335 * Normal Mode : 0x00
14336 * Pre-test Mode : 0x40
14337 * RAM Test Mode : 0x80
14338 * Bit 5 : unused
14339 * Bit 4(RO) : Done bit
14340 * Bit 3-0(RO) : Status
14341 * Host Error : 0x08
14342 * Int_RAM Error : 0x04
14343 * RISC Error : 0x02
14344 * SCSI Error : 0x01
14345 * No Error : 0x00
14346 *
14347 * Note: RAM BIST code should be put right here, before loading the
14348 * microcode and after saving the RISC memory BIOS region.
14349 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014350
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014351 /*
14352 * LRAM Pre-test
14353 *
14354 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14355 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14356 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14357 * to NORMAL_MODE, return an error too.
14358 */
14359 for (i = 0; i < 2; i++) {
14360 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14361 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14362 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14363 if ((byte & RAM_TEST_DONE) == 0
14364 || (byte & 0x0F) != PRE_TEST_VALUE) {
14365 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14366 return ADV_ERROR;
14367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014368
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014369 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14370 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14371 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14372 != NORMAL_VALUE) {
14373 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14374 return ADV_ERROR;
14375 }
14376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014377
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014378 /*
14379 * LRAM Test - It takes about 1.5 ms to run through the test.
14380 *
14381 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14382 * If Done bit not set or Status not 0, save register byte, set the
14383 * err_code, and return an error.
14384 */
14385 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14386 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014387
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014388 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14389 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14390 /* Get here if Done bit not set or Status not 0. */
14391 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14392 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14393 return ADV_ERROR;
14394 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014395
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014396 /* We need to reset back to normal mode after LRAM test passes. */
14397 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014398
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014399 /*
14400 * Load the Microcode
14401 *
14402 * Write the microcode image to RISC memory starting at address 0.
14403 *
14404 */
14405 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014406
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014407 /* Assume the following compressed format of the microcode buffer:
14408 *
14409 * 254 word (508 byte) table indexed by byte code followed
14410 * by the following byte codes:
14411 *
14412 * 1-Byte Code:
14413 * 00: Emit word 0 in table.
14414 * 01: Emit word 1 in table.
14415 * .
14416 * FD: Emit word 253 in table.
14417 *
14418 * Multi-Byte Code:
14419 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14420 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14421 */
14422 word = 0;
14423 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
14424 if (_adv_asc38C0800_buf[i] == 0xff) {
14425 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
14426 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14427 _adv_asc38C0800_buf
14428 [i +
14429 3] << 8) |
14430 _adv_asc38C0800_buf
14431 [i + 2]));
14432 word++;
14433 }
14434 i += 3;
14435 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
14436 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14437 _adv_asc38C0800_buf
14438 [i +
14439 2] << 8) |
14440 _adv_asc38C0800_buf[i
14441 +
14442 1]));
14443 i += 2;
14444 word++;
14445 } else {
14446 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14447 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
14448 word++;
14449 }
14450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014451
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014452 /*
14453 * Set 'word' for later use to clear the rest of memory and save
14454 * the expanded mcode size.
14455 */
14456 word *= 2;
14457 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014458
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014459 /*
14460 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
14461 */
14462 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
14463 AdvWriteWordAutoIncLram(iop_base, 0);
14464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014465
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014466 /*
14467 * Verify the microcode checksum.
14468 */
14469 sum = 0;
14470 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014471
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014472 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
14473 sum += AdvReadWordAutoIncLram(iop_base);
14474 }
14475 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014476
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014477 ASC_DBG2(1,
14478 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
14479 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014481 if (sum != _adv_asc38C0800_chksum) {
14482 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14483 return ADV_ERROR;
14484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014485
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014486 /*
14487 * Restore the RISC memory BIOS region.
14488 */
14489 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14490 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14491 bios_mem[i]);
14492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014494 /*
14495 * Calculate and write the microcode code checksum to the microcode
14496 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14497 */
14498 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14499 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14500 code_sum = 0;
14501 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14502 for (word = begin_addr; word < end_addr; word += 2) {
14503 code_sum += AdvReadWordAutoIncLram(iop_base);
14504 }
14505 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014506
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014507 /*
14508 * Read microcode version and date.
14509 */
14510 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14511 asc_dvc->cfg->mcode_date);
14512 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14513 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014514
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014515 /*
14516 * Set the chip type to indicate the ASC38C0800.
14517 */
14518 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014519
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014520 /*
14521 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
14522 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
14523 * cable detection and then we are able to read C_DET[3:0].
14524 *
14525 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
14526 * Microcode Default Value' section below.
14527 */
14528 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
14529 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
14530 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014531
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014532 /*
14533 * If the PCI Configuration Command Register "Parity Error Response
14534 * Control" Bit was clear (0), then set the microcode variable
14535 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14536 * to ignore DMA parity errors.
14537 */
14538 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14539 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14540 word |= CONTROL_FLAG_IGNORE_PERR;
14541 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014543
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014544 /*
14545 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
14546 * bits for the default FIFO threshold.
14547 *
14548 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
14549 *
14550 * For DMA Errata #4 set the BC_THRESH_ENB bit.
14551 */
14552 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14553 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
14554 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014555
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014556 /*
14557 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040014558 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014559 * device reports it is capable of in Inquiry byte 7.
14560 *
14561 * If SCSI Bus Resets have been disabled, then directly set
14562 * SDTR and WDTR from the EEPROM configuration. This will allow
14563 * the BIOS and warm boot to work without a SCSI bus hang on
14564 * the Inquiry caused by host and target mismatched DTR values.
14565 * Without the SCSI Bus Reset, before an Inquiry a device can't
14566 * be assumed to be in Asynchronous, Narrow mode.
14567 */
14568 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14569 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14570 asc_dvc->wdtr_able);
14571 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14572 asc_dvc->sdtr_able);
14573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014575 /*
14576 * Set microcode operating variables for DISC and SDTR_SPEED1,
14577 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
14578 * configuration values.
14579 *
14580 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14581 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14582 * without determining here whether the device supports SDTR.
14583 */
14584 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14585 asc_dvc->cfg->disc_enable);
14586 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
14587 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
14588 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
14589 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014590
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014591 /*
14592 * Set SCSI_CFG0 Microcode Default Value.
14593 *
14594 * The microcode will set the SCSI_CFG0 register using this value
14595 * after it is started below.
14596 */
14597 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14598 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14599 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014600
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014601 /*
14602 * Determine SCSI_CFG1 Microcode Default Value.
14603 *
14604 * The microcode will set the SCSI_CFG1 register using this value
14605 * after it is started below.
14606 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014607
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014608 /* Read current SCSI_CFG1 Register value. */
14609 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014610
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014611 /*
14612 * If the internal narrow cable is reversed all of the SCSI_CTRL
14613 * register signals will be set. Check for and return an error if
14614 * this condition is found.
14615 */
14616 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14617 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14618 return ADV_ERROR;
14619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014620
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014621 /*
14622 * All kind of combinations of devices attached to one of four connectors
14623 * are acceptable except HVD device attached. For example, LVD device can
14624 * be attached to SE connector while SE device attached to LVD connector.
14625 * If LVD device attached to SE connector, it only runs up to Ultra speed.
14626 *
14627 * If an HVD device is attached to one of LVD connectors, return an error.
14628 * However, there is no way to detect HVD device attached to SE connectors.
14629 */
14630 if (scsi_cfg1 & HVD) {
14631 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
14632 return ADV_ERROR;
14633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014634
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014635 /*
14636 * If either SE or LVD automatic termination control is enabled, then
14637 * set the termination value based on a table listed in a_condor.h.
14638 *
14639 * If manual termination was specified with an EEPROM setting then
14640 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
14641 * be 'ored' into SCSI_CFG1.
14642 */
14643 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
14644 /* SE automatic termination control is enabled. */
14645 switch (scsi_cfg1 & C_DET_SE) {
14646 /* TERM_SE_HI: on, TERM_SE_LO: on */
14647 case 0x1:
14648 case 0x2:
14649 case 0x3:
14650 asc_dvc->cfg->termination |= TERM_SE;
14651 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014653 /* TERM_SE_HI: on, TERM_SE_LO: off */
14654 case 0x0:
14655 asc_dvc->cfg->termination |= TERM_SE_HI;
14656 break;
14657 }
14658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014659
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014660 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
14661 /* LVD automatic termination control is enabled. */
14662 switch (scsi_cfg1 & C_DET_LVD) {
14663 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
14664 case 0x4:
14665 case 0x8:
14666 case 0xC:
14667 asc_dvc->cfg->termination |= TERM_LVD;
14668 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014669
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014670 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
14671 case 0x0:
14672 break;
14673 }
14674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014675
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014676 /*
14677 * Clear any set TERM_SE and TERM_LVD bits.
14678 */
14679 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014680
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014681 /*
14682 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
14683 */
14684 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014685
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014686 /*
14687 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
14688 * and set possibly modified termination control bits in the Microcode
14689 * SCSI_CFG1 Register Value.
14690 */
14691 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014692
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014693 /*
14694 * Set SCSI_CFG1 Microcode Default Value
14695 *
14696 * Set possibly modified termination control and reset DIS_TERM_DRV
14697 * bits in the Microcode SCSI_CFG1 Register Value.
14698 *
14699 * The microcode will set the SCSI_CFG1 register using this value
14700 * after it is started below.
14701 */
14702 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014703
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014704 /*
14705 * Set MEM_CFG Microcode Default Value
14706 *
14707 * The microcode will set the MEM_CFG register using this value
14708 * after it is started below.
14709 *
14710 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14711 * are defined.
14712 *
14713 * ASC-38C0800 has 16KB internal memory.
14714 */
14715 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14716 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014717
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014718 /*
14719 * Set SEL_MASK Microcode Default Value
14720 *
14721 * The microcode will set the SEL_MASK register using this value
14722 * after it is started below.
14723 */
14724 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14725 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014726
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014727 /*
14728 * Build the carrier freelist.
14729 *
14730 * Driver must have already allocated memory and set 'carrier_buf'.
14731 */
14732 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014733
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014734 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14735 asc_dvc->carr_freelist = NULL;
14736 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14737 buf_size = ADV_CARRIER_BUFSIZE;
14738 } else {
14739 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014741
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014742 do {
14743 /*
14744 * Get physical address for the carrier 'carrp'.
14745 */
14746 contig_len = sizeof(ADV_CARR_T);
14747 carr_paddr =
14748 cpu_to_le32(DvcGetPhyAddr
14749 (asc_dvc, NULL, (uchar *)carrp,
14750 (ADV_SDCNT *)&contig_len,
14751 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014752
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014753 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014754
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014755 /*
14756 * If the current carrier is not physically contiguous, then
14757 * maybe there was a page crossing. Try the next carrier aligned
14758 * start address.
14759 */
14760 if (contig_len < sizeof(ADV_CARR_T)) {
14761 carrp++;
14762 continue;
14763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014764
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014765 carrp->carr_pa = carr_paddr;
14766 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014767
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014768 /*
14769 * Insert the carrier at the beginning of the freelist.
14770 */
14771 carrp->next_vpa =
14772 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14773 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014774
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014775 carrp++;
14776 }
14777 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014778
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014779 /*
14780 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14781 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014782
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014783 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14784 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14785 return ADV_ERROR;
14786 }
14787 asc_dvc->carr_freelist = (ADV_CARR_T *)
14788 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014789
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014790 /*
14791 * The first command issued will be placed in the stopper carrier.
14792 */
14793 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014794
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014795 /*
14796 * Set RISC ICQ physical address start value.
14797 * carr_pa is LE, must be native before write
14798 */
14799 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014800
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014801 /*
14802 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14803 */
14804 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14805 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14806 return ADV_ERROR;
14807 }
14808 asc_dvc->carr_freelist = (ADV_CARR_T *)
14809 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014810
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014811 /*
14812 * The first command completed by the RISC will be placed in
14813 * the stopper.
14814 *
14815 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14816 * completed the RISC will set the ASC_RQ_STOPPER bit.
14817 */
14818 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014819
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014820 /*
14821 * Set RISC IRQ physical address start value.
14822 *
14823 * carr_pa is LE, must be native before write *
14824 */
14825 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14826 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014827
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014828 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14829 (ADV_INTR_ENABLE_HOST_INTR |
14830 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014831
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014832 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14833 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014834
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014835 /* finally, finally, gentlemen, start your engine */
14836 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014837
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014838 /*
14839 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14840 * Resets should be performed. The RISC has to be running
14841 * to issue a SCSI Bus Reset.
14842 */
14843 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14844 /*
14845 * If the BIOS Signature is present in memory, restore the
14846 * BIOS Handshake Configuration Table and do not perform
14847 * a SCSI Bus Reset.
14848 */
14849 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14850 0x55AA) {
14851 /*
14852 * Restore per TID negotiated values.
14853 */
14854 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14855 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14856 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14857 tagqng_able);
14858 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14859 AdvWriteByteLram(iop_base,
14860 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14861 max_cmd[tid]);
14862 }
14863 } else {
14864 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14865 warn_code = ASC_WARN_BUSRESET_ERROR;
14866 }
14867 }
14868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014869
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014870 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014871}
14872
14873/*
14874 * Initialize the ASC-38C1600.
14875 *
14876 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
14877 *
14878 * For a non-fatal error return a warning code. If there are no warnings
14879 * then 0 is returned.
14880 *
14881 * Needed after initialization for error recovery.
14882 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014883static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014884{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014885 AdvPortAddr iop_base;
14886 ushort warn_code;
14887 ADV_DCNT sum;
14888 int begin_addr;
14889 int end_addr;
14890 ushort code_sum;
14891 long word;
14892 int j;
14893 int adv_asc38C1600_expanded_size;
14894 ADV_CARR_T *carrp;
14895 ADV_DCNT contig_len;
14896 ADV_SDCNT buf_size;
14897 ADV_PADDR carr_paddr;
14898 int i;
14899 ushort scsi_cfg1;
14900 uchar byte;
14901 uchar tid;
14902 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14903 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
14904 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014905
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014906 /* If there is already an error, don't continue. */
14907 if (asc_dvc->err_code != 0) {
14908 return ADV_ERROR;
14909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014910
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014911 /*
14912 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
14913 */
14914 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
14915 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14916 return ADV_ERROR;
14917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014918
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014919 warn_code = 0;
14920 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014921
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014922 /*
14923 * Save the RISC memory BIOS region before writing the microcode.
14924 * The BIOS may already be loaded and using its RISC LRAM region
14925 * so its region must be saved and restored.
14926 *
14927 * Note: This code makes the assumption, which is currently true,
14928 * that a chip reset does not clear RISC LRAM.
14929 */
14930 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14931 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14932 bios_mem[i]);
14933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014934
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014935 /*
14936 * Save current per TID negotiated values.
14937 */
14938 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14939 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14940 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
14941 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14942 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
14943 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14944 max_cmd[tid]);
14945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014946
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014947 /*
14948 * RAM BIST (Built-In Self Test)
14949 *
14950 * Address : I/O base + offset 0x38h register (byte).
14951 * Function: Bit 7-6(RW) : RAM mode
14952 * Normal Mode : 0x00
14953 * Pre-test Mode : 0x40
14954 * RAM Test Mode : 0x80
14955 * Bit 5 : unused
14956 * Bit 4(RO) : Done bit
14957 * Bit 3-0(RO) : Status
14958 * Host Error : 0x08
14959 * Int_RAM Error : 0x04
14960 * RISC Error : 0x02
14961 * SCSI Error : 0x01
14962 * No Error : 0x00
14963 *
14964 * Note: RAM BIST code should be put right here, before loading the
14965 * microcode and after saving the RISC memory BIOS region.
14966 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014967
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014968 /*
14969 * LRAM Pre-test
14970 *
14971 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14972 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14973 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14974 * to NORMAL_MODE, return an error too.
14975 */
14976 for (i = 0; i < 2; i++) {
14977 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14978 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14979 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14980 if ((byte & RAM_TEST_DONE) == 0
14981 || (byte & 0x0F) != PRE_TEST_VALUE) {
14982 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14983 return ADV_ERROR;
14984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014985
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014986 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14987 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14988 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14989 != NORMAL_VALUE) {
14990 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14991 return ADV_ERROR;
14992 }
14993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014994
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014995 /*
14996 * LRAM Test - It takes about 1.5 ms to run through the test.
14997 *
14998 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14999 * If Done bit not set or Status not 0, save register byte, set the
15000 * err_code, and return an error.
15001 */
15002 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
15003 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015004
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015005 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15006 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
15007 /* Get here if Done bit not set or Status not 0. */
15008 asc_dvc->bist_err_code = byte; /* for BIOS display message */
15009 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
15010 return ADV_ERROR;
15011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015012
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015013 /* We need to reset back to normal mode after LRAM test passes. */
15014 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015015
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015016 /*
15017 * Load the Microcode
15018 *
15019 * Write the microcode image to RISC memory starting at address 0.
15020 *
15021 */
15022 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015023
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015024 /*
15025 * Assume the following compressed format of the microcode buffer:
15026 *
15027 * 254 word (508 byte) table indexed by byte code followed
15028 * by the following byte codes:
15029 *
15030 * 1-Byte Code:
15031 * 00: Emit word 0 in table.
15032 * 01: Emit word 1 in table.
15033 * .
15034 * FD: Emit word 253 in table.
15035 *
15036 * Multi-Byte Code:
15037 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15038 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15039 */
15040 word = 0;
15041 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
15042 if (_adv_asc38C1600_buf[i] == 0xff) {
15043 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
15044 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15045 _adv_asc38C1600_buf
15046 [i +
15047 3] << 8) |
15048 _adv_asc38C1600_buf
15049 [i + 2]));
15050 word++;
15051 }
15052 i += 3;
15053 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
15054 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15055 _adv_asc38C1600_buf
15056 [i +
15057 2] << 8) |
15058 _adv_asc38C1600_buf[i
15059 +
15060 1]));
15061 i += 2;
15062 word++;
15063 } else {
15064 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15065 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
15066 word++;
15067 }
15068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015069
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015070 /*
15071 * Set 'word' for later use to clear the rest of memory and save
15072 * the expanded mcode size.
15073 */
15074 word *= 2;
15075 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015076
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015077 /*
15078 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15079 */
15080 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15081 AdvWriteWordAutoIncLram(iop_base, 0);
15082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015083
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015084 /*
15085 * Verify the microcode checksum.
15086 */
15087 sum = 0;
15088 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015089
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015090 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15091 sum += AdvReadWordAutoIncLram(iop_base);
15092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015094 if (sum != _adv_asc38C1600_chksum) {
15095 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15096 return ADV_ERROR;
15097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015098
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015099 /*
15100 * Restore the RISC memory BIOS region.
15101 */
15102 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15103 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15104 bios_mem[i]);
15105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015106
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015107 /*
15108 * Calculate and write the microcode code checksum to the microcode
15109 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15110 */
15111 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15112 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15113 code_sum = 0;
15114 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15115 for (word = begin_addr; word < end_addr; word += 2) {
15116 code_sum += AdvReadWordAutoIncLram(iop_base);
15117 }
15118 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015119
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015120 /*
15121 * Read microcode version and date.
15122 */
15123 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15124 asc_dvc->cfg->mcode_date);
15125 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15126 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015127
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015128 /*
15129 * Set the chip type to indicate the ASC38C1600.
15130 */
15131 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015132
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015133 /*
15134 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15135 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15136 * cable detection and then we are able to read C_DET[3:0].
15137 *
15138 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15139 * Microcode Default Value' section below.
15140 */
15141 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15142 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15143 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015144
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015145 /*
15146 * If the PCI Configuration Command Register "Parity Error Response
15147 * Control" Bit was clear (0), then set the microcode variable
15148 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15149 * to ignore DMA parity errors.
15150 */
15151 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15152 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15153 word |= CONTROL_FLAG_IGNORE_PERR;
15154 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015156
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015157 /*
15158 * If the BIOS control flag AIPP (Asynchronous Information
15159 * Phase Protection) disable bit is not set, then set the firmware
15160 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15161 * AIPP checking and encoding.
15162 */
15163 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15164 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15165 word |= CONTROL_FLAG_ENABLE_AIPP;
15166 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015168
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015169 /*
15170 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15171 * and START_CTL_TH [3:2].
15172 */
15173 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15174 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015176 /*
15177 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040015178 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015179 * device reports it is capable of in Inquiry byte 7.
15180 *
15181 * If SCSI Bus Resets have been disabled, then directly set
15182 * SDTR and WDTR from the EEPROM configuration. This will allow
15183 * the BIOS and warm boot to work without a SCSI bus hang on
15184 * the Inquiry caused by host and target mismatched DTR values.
15185 * Without the SCSI Bus Reset, before an Inquiry a device can't
15186 * be assumed to be in Asynchronous, Narrow mode.
15187 */
15188 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15189 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15190 asc_dvc->wdtr_able);
15191 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15192 asc_dvc->sdtr_able);
15193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015194
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015195 /*
15196 * Set microcode operating variables for DISC and SDTR_SPEED1,
15197 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15198 * configuration values.
15199 *
15200 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15201 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15202 * without determining here whether the device supports SDTR.
15203 */
15204 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15205 asc_dvc->cfg->disc_enable);
15206 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15207 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15208 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15209 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015210
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015211 /*
15212 * Set SCSI_CFG0 Microcode Default Value.
15213 *
15214 * The microcode will set the SCSI_CFG0 register using this value
15215 * after it is started below.
15216 */
15217 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15218 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15219 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015220
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015221 /*
15222 * Calculate SCSI_CFG1 Microcode Default Value.
15223 *
15224 * The microcode will set the SCSI_CFG1 register using this value
15225 * after it is started below.
15226 *
15227 * Each ASC-38C1600 function has only two cable detect bits.
15228 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15229 */
15230 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015231
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015232 /*
15233 * If the cable is reversed all of the SCSI_CTRL register signals
15234 * will be set. Check for and return an error if this condition is
15235 * found.
15236 */
15237 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15238 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15239 return ADV_ERROR;
15240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015241
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015242 /*
15243 * Each ASC-38C1600 function has two connectors. Only an HVD device
15244 * can not be connected to either connector. An LVD device or SE device
15245 * may be connected to either connecor. If an SE device is connected,
15246 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15247 *
15248 * If an HVD device is attached, return an error.
15249 */
15250 if (scsi_cfg1 & HVD) {
15251 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15252 return ADV_ERROR;
15253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015254
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015255 /*
15256 * Each function in the ASC-38C1600 uses only the SE cable detect and
15257 * termination because there are two connectors for each function. Each
15258 * function may use either LVD or SE mode. Corresponding the SE automatic
15259 * termination control EEPROM bits are used for each function. Each
15260 * function has its own EEPROM. If SE automatic control is enabled for
15261 * the function, then set the termination value based on a table listed
15262 * in a_condor.h.
15263 *
15264 * If manual termination is specified in the EEPROM for the function,
15265 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15266 * ready to be 'ored' into SCSI_CFG1.
15267 */
15268 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15269 /* SE automatic termination control is enabled. */
15270 switch (scsi_cfg1 & C_DET_SE) {
15271 /* TERM_SE_HI: on, TERM_SE_LO: on */
15272 case 0x1:
15273 case 0x2:
15274 case 0x3:
15275 asc_dvc->cfg->termination |= TERM_SE;
15276 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015277
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015278 case 0x0:
15279 if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
15280 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15281 } else {
15282 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15283 asc_dvc->cfg->termination |= TERM_SE_HI;
15284 }
15285 break;
15286 }
15287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015288
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015289 /*
15290 * Clear any set TERM_SE bits.
15291 */
15292 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015293
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015294 /*
15295 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15296 */
15297 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015298
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015299 /*
15300 * Clear Big Endian and Terminator Polarity bits and set possibly
15301 * modified termination control bits in the Microcode SCSI_CFG1
15302 * Register Value.
15303 *
15304 * Big Endian bit is not used even on big endian machines.
15305 */
15306 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015307
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015308 /*
15309 * Set SCSI_CFG1 Microcode Default Value
15310 *
15311 * Set possibly modified termination control bits in the Microcode
15312 * SCSI_CFG1 Register Value.
15313 *
15314 * The microcode will set the SCSI_CFG1 register using this value
15315 * after it is started below.
15316 */
15317 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015318
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015319 /*
15320 * Set MEM_CFG Microcode Default Value
15321 *
15322 * The microcode will set the MEM_CFG register using this value
15323 * after it is started below.
15324 *
15325 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15326 * are defined.
15327 *
15328 * ASC-38C1600 has 32KB internal memory.
15329 *
15330 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15331 * out a special 16K Adv Library and Microcode version. After the issue
15332 * resolved, we should turn back to the 32K support. Both a_condor.h and
15333 * mcode.sas files also need to be updated.
15334 *
15335 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15336 * BIOS_EN | RAM_SZ_32KB);
15337 */
15338 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15339 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015340
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015341 /*
15342 * Set SEL_MASK Microcode Default Value
15343 *
15344 * The microcode will set the SEL_MASK register using this value
15345 * after it is started below.
15346 */
15347 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15348 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015349
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015350 /*
15351 * Build the carrier freelist.
15352 *
15353 * Driver must have already allocated memory and set 'carrier_buf'.
15354 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015355
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015356 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015357
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015358 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15359 asc_dvc->carr_freelist = NULL;
15360 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15361 buf_size = ADV_CARRIER_BUFSIZE;
15362 } else {
15363 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015365
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015366 do {
15367 /*
15368 * Get physical address for the carrier 'carrp'.
15369 */
15370 contig_len = sizeof(ADV_CARR_T);
15371 carr_paddr =
15372 cpu_to_le32(DvcGetPhyAddr
15373 (asc_dvc, NULL, (uchar *)carrp,
15374 (ADV_SDCNT *)&contig_len,
15375 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015376
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015377 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015378
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015379 /*
15380 * If the current carrier is not physically contiguous, then
15381 * maybe there was a page crossing. Try the next carrier aligned
15382 * start address.
15383 */
15384 if (contig_len < sizeof(ADV_CARR_T)) {
15385 carrp++;
15386 continue;
15387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015388
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015389 carrp->carr_pa = carr_paddr;
15390 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015391
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015392 /*
15393 * Insert the carrier at the beginning of the freelist.
15394 */
15395 carrp->next_vpa =
15396 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15397 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015398
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015399 carrp++;
15400 }
15401 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015402
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015403 /*
15404 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15405 */
15406 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15407 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15408 return ADV_ERROR;
15409 }
15410 asc_dvc->carr_freelist = (ADV_CARR_T *)
15411 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015412
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015413 /*
15414 * The first command issued will be placed in the stopper carrier.
15415 */
15416 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015417
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015418 /*
15419 * Set RISC ICQ physical address start value. Initialize the
15420 * COMMA register to the same value otherwise the RISC will
15421 * prematurely detect a command is available.
15422 */
15423 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
15424 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
15425 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015426
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015427 /*
15428 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15429 */
15430 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15431 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15432 return ADV_ERROR;
15433 }
15434 asc_dvc->carr_freelist = (ADV_CARR_T *)
15435 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015436
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015437 /*
15438 * The first command completed by the RISC will be placed in
15439 * the stopper.
15440 *
15441 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15442 * completed the RISC will set the ASC_RQ_STOPPER bit.
15443 */
15444 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015445
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015446 /*
15447 * Set RISC IRQ physical address start value.
15448 */
15449 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15450 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015451
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015452 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15453 (ADV_INTR_ENABLE_HOST_INTR |
15454 ADV_INTR_ENABLE_GLOBAL_INTR));
15455 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15456 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015457
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015458 /* finally, finally, gentlemen, start your engine */
15459 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015460
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015461 /*
15462 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15463 * Resets should be performed. The RISC has to be running
15464 * to issue a SCSI Bus Reset.
15465 */
15466 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15467 /*
15468 * If the BIOS Signature is present in memory, restore the
15469 * per TID microcode operating variables.
15470 */
15471 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15472 0x55AA) {
15473 /*
15474 * Restore per TID negotiated values.
15475 */
15476 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15477 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15478 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15479 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15480 tagqng_able);
15481 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15482 AdvWriteByteLram(iop_base,
15483 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15484 max_cmd[tid]);
15485 }
15486 } else {
15487 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15488 warn_code = ASC_WARN_BUSRESET_ERROR;
15489 }
15490 }
15491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015492
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015493 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015494}
15495
15496/*
15497 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15498 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15499 * all of this is done.
15500 *
15501 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15502 *
15503 * For a non-fatal error return a warning code. If there are no warnings
15504 * then 0 is returned.
15505 *
15506 * Note: Chip is stopped on entry.
15507 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015508static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015509{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015510 AdvPortAddr iop_base;
15511 ushort warn_code;
15512 ADVEEP_3550_CONFIG eep_config;
15513 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015514
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015515 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015516
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015517 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015518
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015519 /*
15520 * Read the board's EEPROM configuration.
15521 *
15522 * Set default values if a bad checksum is found.
15523 */
15524 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
15525 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015526
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015527 /*
15528 * Set EEPROM default values.
15529 */
15530 for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
15531 *((uchar *)&eep_config + i) =
15532 *((uchar *)&Default_3550_EEPROM_Config + i);
15533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015535 /*
15536 * Assume the 6 byte board serial number that was read
15537 * from EEPROM is correct even if the EEPROM checksum
15538 * failed.
15539 */
15540 eep_config.serial_number_word3 =
15541 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015542
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015543 eep_config.serial_number_word2 =
15544 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015545
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015546 eep_config.serial_number_word1 =
15547 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015548
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015549 AdvSet3550EEPConfig(iop_base, &eep_config);
15550 }
15551 /*
15552 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15553 * EEPROM configuration that was read.
15554 *
15555 * This is the mapping of EEPROM fields to Adv Library fields.
15556 */
15557 asc_dvc->wdtr_able = eep_config.wdtr_able;
15558 asc_dvc->sdtr_able = eep_config.sdtr_able;
15559 asc_dvc->ultra_able = eep_config.ultra_able;
15560 asc_dvc->tagqng_able = eep_config.tagqng_able;
15561 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15562 asc_dvc->max_host_qng = eep_config.max_host_qng;
15563 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15564 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15565 asc_dvc->start_motor = eep_config.start_motor;
15566 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15567 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15568 asc_dvc->no_scam = eep_config.scam_tolerant;
15569 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15570 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15571 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015572
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015573 /*
15574 * Set the host maximum queuing (max. 253, min. 16) and the per device
15575 * maximum queuing (max. 63, min. 4).
15576 */
15577 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15578 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15579 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15580 /* If the value is zero, assume it is uninitialized. */
15581 if (eep_config.max_host_qng == 0) {
15582 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15583 } else {
15584 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15585 }
15586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015587
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015588 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15589 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15590 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15591 /* If the value is zero, assume it is uninitialized. */
15592 if (eep_config.max_dvc_qng == 0) {
15593 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15594 } else {
15595 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15596 }
15597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015598
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015599 /*
15600 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15601 * set 'max_dvc_qng' to 'max_host_qng'.
15602 */
15603 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15604 eep_config.max_dvc_qng = eep_config.max_host_qng;
15605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015606
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015607 /*
15608 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15609 * values based on possibly adjusted EEPROM values.
15610 */
15611 asc_dvc->max_host_qng = eep_config.max_host_qng;
15612 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015613
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015614 /*
15615 * If the EEPROM 'termination' field is set to automatic (0), then set
15616 * the ADV_DVC_CFG 'termination' field to automatic also.
15617 *
15618 * If the termination is specified with a non-zero 'termination'
15619 * value check that a legal value is set and set the ADV_DVC_CFG
15620 * 'termination' field appropriately.
15621 */
15622 if (eep_config.termination == 0) {
15623 asc_dvc->cfg->termination = 0; /* auto termination */
15624 } else {
15625 /* Enable manual control with low off / high off. */
15626 if (eep_config.termination == 1) {
15627 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015629 /* Enable manual control with low off / high on. */
15630 } else if (eep_config.termination == 2) {
15631 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015632
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015633 /* Enable manual control with low on / high on. */
15634 } else if (eep_config.termination == 3) {
15635 asc_dvc->cfg->termination =
15636 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
15637 } else {
15638 /*
15639 * The EEPROM 'termination' field contains a bad value. Use
15640 * automatic termination instead.
15641 */
15642 asc_dvc->cfg->termination = 0;
15643 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15644 }
15645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015646
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015647 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015648}
15649
15650/*
15651 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15652 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15653 * all of this is done.
15654 *
15655 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15656 *
15657 * For a non-fatal error return a warning code. If there are no warnings
15658 * then 0 is returned.
15659 *
15660 * Note: Chip is stopped on entry.
15661 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015662static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015663{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015664 AdvPortAddr iop_base;
15665 ushort warn_code;
15666 ADVEEP_38C0800_CONFIG eep_config;
15667 int i;
15668 uchar tid, termination;
15669 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015670
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015671 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015672
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015673 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015674
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015675 /*
15676 * Read the board's EEPROM configuration.
15677 *
15678 * Set default values if a bad checksum is found.
15679 */
15680 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
15681 eep_config.check_sum) {
15682 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015683
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015684 /*
15685 * Set EEPROM default values.
15686 */
15687 for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
15688 *((uchar *)&eep_config + i) =
15689 *((uchar *)&Default_38C0800_EEPROM_Config + i);
15690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015692 /*
15693 * Assume the 6 byte board serial number that was read
15694 * from EEPROM is correct even if the EEPROM checksum
15695 * failed.
15696 */
15697 eep_config.serial_number_word3 =
15698 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015699
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015700 eep_config.serial_number_word2 =
15701 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015702
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015703 eep_config.serial_number_word1 =
15704 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015705
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015706 AdvSet38C0800EEPConfig(iop_base, &eep_config);
15707 }
15708 /*
15709 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
15710 * EEPROM configuration that was read.
15711 *
15712 * This is the mapping of EEPROM fields to Adv Library fields.
15713 */
15714 asc_dvc->wdtr_able = eep_config.wdtr_able;
15715 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15716 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15717 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15718 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15719 asc_dvc->tagqng_able = eep_config.tagqng_able;
15720 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15721 asc_dvc->max_host_qng = eep_config.max_host_qng;
15722 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15723 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15724 asc_dvc->start_motor = eep_config.start_motor;
15725 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15726 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15727 asc_dvc->no_scam = eep_config.scam_tolerant;
15728 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15729 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15730 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015731
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015732 /*
15733 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15734 * are set, then set an 'sdtr_able' bit for it.
15735 */
15736 asc_dvc->sdtr_able = 0;
15737 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15738 if (tid == 0) {
15739 sdtr_speed = asc_dvc->sdtr_speed1;
15740 } else if (tid == 4) {
15741 sdtr_speed = asc_dvc->sdtr_speed2;
15742 } else if (tid == 8) {
15743 sdtr_speed = asc_dvc->sdtr_speed3;
15744 } else if (tid == 12) {
15745 sdtr_speed = asc_dvc->sdtr_speed4;
15746 }
15747 if (sdtr_speed & ADV_MAX_TID) {
15748 asc_dvc->sdtr_able |= (1 << tid);
15749 }
15750 sdtr_speed >>= 4;
15751 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015752
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015753 /*
15754 * Set the host maximum queuing (max. 253, min. 16) and the per device
15755 * maximum queuing (max. 63, min. 4).
15756 */
15757 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15758 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15759 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15760 /* If the value is zero, assume it is uninitialized. */
15761 if (eep_config.max_host_qng == 0) {
15762 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15763 } else {
15764 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15765 }
15766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015767
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015768 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15769 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15770 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15771 /* If the value is zero, assume it is uninitialized. */
15772 if (eep_config.max_dvc_qng == 0) {
15773 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15774 } else {
15775 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15776 }
15777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015778
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015779 /*
15780 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15781 * set 'max_dvc_qng' to 'max_host_qng'.
15782 */
15783 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15784 eep_config.max_dvc_qng = eep_config.max_host_qng;
15785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015786
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015787 /*
15788 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15789 * values based on possibly adjusted EEPROM values.
15790 */
15791 asc_dvc->max_host_qng = eep_config.max_host_qng;
15792 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015793
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015794 /*
15795 * If the EEPROM 'termination' field is set to automatic (0), then set
15796 * the ADV_DVC_CFG 'termination' field to automatic also.
15797 *
15798 * If the termination is specified with a non-zero 'termination'
15799 * value check that a legal value is set and set the ADV_DVC_CFG
15800 * 'termination' field appropriately.
15801 */
15802 if (eep_config.termination_se == 0) {
15803 termination = 0; /* auto termination for SE */
15804 } else {
15805 /* Enable manual control with low off / high off. */
15806 if (eep_config.termination_se == 1) {
15807 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015808
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015809 /* Enable manual control with low off / high on. */
15810 } else if (eep_config.termination_se == 2) {
15811 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015812
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015813 /* Enable manual control with low on / high on. */
15814 } else if (eep_config.termination_se == 3) {
15815 termination = TERM_SE;
15816 } else {
15817 /*
15818 * The EEPROM 'termination_se' field contains a bad value.
15819 * Use automatic termination instead.
15820 */
15821 termination = 0;
15822 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15823 }
15824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015825
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015826 if (eep_config.termination_lvd == 0) {
15827 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
15828 } else {
15829 /* Enable manual control with low off / high off. */
15830 if (eep_config.termination_lvd == 1) {
15831 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015832
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015833 /* Enable manual control with low off / high on. */
15834 } else if (eep_config.termination_lvd == 2) {
15835 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015837 /* Enable manual control with low on / high on. */
15838 } else if (eep_config.termination_lvd == 3) {
15839 asc_dvc->cfg->termination = termination | TERM_LVD;
15840 } else {
15841 /*
15842 * The EEPROM 'termination_lvd' field contains a bad value.
15843 * Use automatic termination instead.
15844 */
15845 asc_dvc->cfg->termination = termination;
15846 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15847 }
15848 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015849
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015850 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015851}
15852
15853/*
15854 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
15855 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
15856 * all of this is done.
15857 *
15858 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15859 *
15860 * For a non-fatal error return a warning code. If there are no warnings
15861 * then 0 is returned.
15862 *
15863 * Note: Chip is stopped on entry.
15864 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015865static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015866{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015867 AdvPortAddr iop_base;
15868 ushort warn_code;
15869 ADVEEP_38C1600_CONFIG eep_config;
15870 int i;
15871 uchar tid, termination;
15872 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015873
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015874 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015875
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015876 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015877
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015878 /*
15879 * Read the board's EEPROM configuration.
15880 *
15881 * Set default values if a bad checksum is found.
15882 */
15883 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
15884 eep_config.check_sum) {
15885 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015886
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015887 /*
15888 * Set EEPROM default values.
15889 */
15890 for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
15891 if (i == 1
15892 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
15893 0) {
15894 /*
15895 * Set Function 1 EEPROM Word 0 MSB
15896 *
15897 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
15898 * EEPROM bits.
15899 *
15900 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
15901 * old Mac system booting problem. The Expansion ROM must
15902 * be disabled in Function 1 for these systems.
15903 *
15904 */
15905 *((uchar *)&eep_config + i) =
15906 ((*
15907 ((uchar *)&Default_38C1600_EEPROM_Config
15908 +
15909 i)) &
15910 (~
15911 (((ADV_EEPROM_BIOS_ENABLE |
15912 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015913
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015914 /*
15915 * Set the INTAB (bit 11) if the GPIO 0 input indicates
15916 * the Function 1 interrupt line is wired to INTA.
15917 *
15918 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
15919 * 1 - Function 1 interrupt line wired to INT A.
15920 * 0 - Function 1 interrupt line wired to INT B.
15921 *
15922 * Note: Adapter boards always have Function 0 wired to INTA.
15923 * Put all 5 GPIO bits in input mode and then read
15924 * their input values.
15925 */
15926 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
15927 0);
15928 if (AdvReadByteRegister
15929 (iop_base, IOPB_GPIO_DATA) & 0x01) {
15930 /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
15931 *((uchar *)&eep_config + i) |=
15932 ((ADV_EEPROM_INTAB >> 8) & 0xFF);
15933 }
15934 } else {
15935 *((uchar *)&eep_config + i) =
15936 *((uchar *)&Default_38C1600_EEPROM_Config
15937 + i);
15938 }
15939 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015940
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015941 /*
15942 * Assume the 6 byte board serial number that was read
15943 * from EEPROM is correct even if the EEPROM checksum
15944 * failed.
15945 */
15946 eep_config.serial_number_word3 =
15947 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015948
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015949 eep_config.serial_number_word2 =
15950 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015951
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015952 eep_config.serial_number_word1 =
15953 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015954
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015955 AdvSet38C1600EEPConfig(iop_base, &eep_config);
15956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015957
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015958 /*
15959 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15960 * EEPROM configuration that was read.
15961 *
15962 * This is the mapping of EEPROM fields to Adv Library fields.
15963 */
15964 asc_dvc->wdtr_able = eep_config.wdtr_able;
15965 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15966 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15967 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15968 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15969 asc_dvc->ppr_able = 0;
15970 asc_dvc->tagqng_able = eep_config.tagqng_able;
15971 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15972 asc_dvc->max_host_qng = eep_config.max_host_qng;
15973 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15974 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
15975 asc_dvc->start_motor = eep_config.start_motor;
15976 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15977 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15978 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015979
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015980 /*
15981 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15982 * are set, then set an 'sdtr_able' bit for it.
15983 */
15984 asc_dvc->sdtr_able = 0;
15985 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15986 if (tid == 0) {
15987 sdtr_speed = asc_dvc->sdtr_speed1;
15988 } else if (tid == 4) {
15989 sdtr_speed = asc_dvc->sdtr_speed2;
15990 } else if (tid == 8) {
15991 sdtr_speed = asc_dvc->sdtr_speed3;
15992 } else if (tid == 12) {
15993 sdtr_speed = asc_dvc->sdtr_speed4;
15994 }
15995 if (sdtr_speed & ASC_MAX_TID) {
15996 asc_dvc->sdtr_able |= (1 << tid);
15997 }
15998 sdtr_speed >>= 4;
15999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016000
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016001 /*
16002 * Set the host maximum queuing (max. 253, min. 16) and the per device
16003 * maximum queuing (max. 63, min. 4).
16004 */
16005 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16006 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16007 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16008 /* If the value is zero, assume it is uninitialized. */
16009 if (eep_config.max_host_qng == 0) {
16010 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16011 } else {
16012 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16013 }
16014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016015
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016016 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16017 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16018 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16019 /* If the value is zero, assume it is uninitialized. */
16020 if (eep_config.max_dvc_qng == 0) {
16021 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16022 } else {
16023 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16024 }
16025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016026
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016027 /*
16028 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16029 * set 'max_dvc_qng' to 'max_host_qng'.
16030 */
16031 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16032 eep_config.max_dvc_qng = eep_config.max_host_qng;
16033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016034
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016035 /*
16036 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
16037 * values based on possibly adjusted EEPROM values.
16038 */
16039 asc_dvc->max_host_qng = eep_config.max_host_qng;
16040 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016041
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016042 /*
16043 * If the EEPROM 'termination' field is set to automatic (0), then set
16044 * the ASC_DVC_CFG 'termination' field to automatic also.
16045 *
16046 * If the termination is specified with a non-zero 'termination'
16047 * value check that a legal value is set and set the ASC_DVC_CFG
16048 * 'termination' field appropriately.
16049 */
16050 if (eep_config.termination_se == 0) {
16051 termination = 0; /* auto termination for SE */
16052 } else {
16053 /* Enable manual control with low off / high off. */
16054 if (eep_config.termination_se == 1) {
16055 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016056
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016057 /* Enable manual control with low off / high on. */
16058 } else if (eep_config.termination_se == 2) {
16059 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016060
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016061 /* Enable manual control with low on / high on. */
16062 } else if (eep_config.termination_se == 3) {
16063 termination = TERM_SE;
16064 } else {
16065 /*
16066 * The EEPROM 'termination_se' field contains a bad value.
16067 * Use automatic termination instead.
16068 */
16069 termination = 0;
16070 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16071 }
16072 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016073
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016074 if (eep_config.termination_lvd == 0) {
16075 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16076 } else {
16077 /* Enable manual control with low off / high off. */
16078 if (eep_config.termination_lvd == 1) {
16079 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016080
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016081 /* Enable manual control with low off / high on. */
16082 } else if (eep_config.termination_lvd == 2) {
16083 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016084
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016085 /* Enable manual control with low on / high on. */
16086 } else if (eep_config.termination_lvd == 3) {
16087 asc_dvc->cfg->termination = termination | TERM_LVD;
16088 } else {
16089 /*
16090 * The EEPROM 'termination_lvd' field contains a bad value.
16091 * Use automatic termination instead.
16092 */
16093 asc_dvc->cfg->termination = termination;
16094 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16095 }
16096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016097
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016098 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016099}
16100
16101/*
16102 * Read EEPROM configuration into the specified buffer.
16103 *
16104 * Return a checksum based on the EEPROM configuration read.
16105 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016106static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016107AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16108{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016109 ushort wval, chksum;
16110 ushort *wbuf;
16111 int eep_addr;
16112 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016113
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016114 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16115 wbuf = (ushort *)cfg_buf;
16116 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016117
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016118 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16119 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16120 wval = AdvReadEEPWord(iop_base, eep_addr);
16121 chksum += wval; /* Checksum is calculated from word values. */
16122 if (*charfields++) {
16123 *wbuf = le16_to_cpu(wval);
16124 } else {
16125 *wbuf = wval;
16126 }
16127 }
16128 /* Read checksum word. */
16129 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16130 wbuf++;
16131 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016132
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016133 /* Read rest of EEPROM not covered by the checksum. */
16134 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16135 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16136 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16137 if (*charfields++) {
16138 *wbuf = le16_to_cpu(*wbuf);
16139 }
16140 }
16141 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016142}
16143
16144/*
16145 * Read EEPROM configuration into the specified buffer.
16146 *
16147 * Return a checksum based on the EEPROM configuration read.
16148 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016149static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016150AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016151{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016152 ushort wval, chksum;
16153 ushort *wbuf;
16154 int eep_addr;
16155 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016156
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016157 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16158 wbuf = (ushort *)cfg_buf;
16159 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016160
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016161 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16162 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16163 wval = AdvReadEEPWord(iop_base, eep_addr);
16164 chksum += wval; /* Checksum is calculated from word values. */
16165 if (*charfields++) {
16166 *wbuf = le16_to_cpu(wval);
16167 } else {
16168 *wbuf = wval;
16169 }
16170 }
16171 /* Read checksum word. */
16172 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16173 wbuf++;
16174 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016176 /* Read rest of EEPROM not covered by the checksum. */
16177 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16178 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16179 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16180 if (*charfields++) {
16181 *wbuf = le16_to_cpu(*wbuf);
16182 }
16183 }
16184 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016185}
16186
16187/*
16188 * Read EEPROM configuration into the specified buffer.
16189 *
16190 * Return a checksum based on the EEPROM configuration read.
16191 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016192static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016193AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016194{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016195 ushort wval, chksum;
16196 ushort *wbuf;
16197 int eep_addr;
16198 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016199
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016200 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16201 wbuf = (ushort *)cfg_buf;
16202 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016203
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016204 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16205 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16206 wval = AdvReadEEPWord(iop_base, eep_addr);
16207 chksum += wval; /* Checksum is calculated from word values. */
16208 if (*charfields++) {
16209 *wbuf = le16_to_cpu(wval);
16210 } else {
16211 *wbuf = wval;
16212 }
16213 }
16214 /* Read checksum word. */
16215 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16216 wbuf++;
16217 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016218
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016219 /* Read rest of EEPROM not covered by the checksum. */
16220 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16221 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16222 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16223 if (*charfields++) {
16224 *wbuf = le16_to_cpu(*wbuf);
16225 }
16226 }
16227 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016228}
16229
16230/*
16231 * Read the EEPROM from specified location
16232 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016233static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016234{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016235 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16236 ASC_EEP_CMD_READ | eep_word_addr);
16237 AdvWaitEEPCmd(iop_base);
16238 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016239}
16240
16241/*
16242 * Wait for EEPROM command to complete
16243 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016244static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016245{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016246 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016247
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016248 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16249 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16250 ASC_EEP_CMD_DONE) {
16251 break;
16252 }
16253 DvcSleepMilliSecond(1);
16254 }
16255 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16256 0) {
16257 ASC_ASSERT(0);
16258 }
16259 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016260}
16261
16262/*
16263 * Write the EEPROM from 'cfg_buf'.
16264 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016265void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016266AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16267{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016268 ushort *wbuf;
16269 ushort addr, chksum;
16270 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016271
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016272 wbuf = (ushort *)cfg_buf;
16273 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16274 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016275
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016276 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16277 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016278
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016279 /*
16280 * Write EEPROM from word 0 to word 20.
16281 */
16282 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16283 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16284 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016285
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016286 if (*charfields++) {
16287 word = cpu_to_le16(*wbuf);
16288 } else {
16289 word = *wbuf;
16290 }
16291 chksum += *wbuf; /* Checksum is calculated from word values. */
16292 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16293 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16294 ASC_EEP_CMD_WRITE | addr);
16295 AdvWaitEEPCmd(iop_base);
16296 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016298
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016299 /*
16300 * Write EEPROM checksum at word 21.
16301 */
16302 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16303 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16304 AdvWaitEEPCmd(iop_base);
16305 wbuf++;
16306 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016307
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016308 /*
16309 * Write EEPROM OEM name at words 22 to 29.
16310 */
16311 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16312 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16313 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016314
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016315 if (*charfields++) {
16316 word = cpu_to_le16(*wbuf);
16317 } else {
16318 word = *wbuf;
16319 }
16320 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16321 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16322 ASC_EEP_CMD_WRITE | addr);
16323 AdvWaitEEPCmd(iop_base);
16324 }
16325 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16326 AdvWaitEEPCmd(iop_base);
16327 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016328}
16329
16330/*
16331 * Write the EEPROM from 'cfg_buf'.
16332 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016333void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016334AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016335{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016336 ushort *wbuf;
16337 ushort *charfields;
16338 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016339
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016340 wbuf = (ushort *)cfg_buf;
16341 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16342 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016343
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016344 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16345 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016346
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016347 /*
16348 * Write EEPROM from word 0 to word 20.
16349 */
16350 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16351 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16352 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016353
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016354 if (*charfields++) {
16355 word = cpu_to_le16(*wbuf);
16356 } else {
16357 word = *wbuf;
16358 }
16359 chksum += *wbuf; /* Checksum is calculated from word values. */
16360 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16361 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16362 ASC_EEP_CMD_WRITE | addr);
16363 AdvWaitEEPCmd(iop_base);
16364 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016366
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016367 /*
16368 * Write EEPROM checksum at word 21.
16369 */
16370 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16371 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16372 AdvWaitEEPCmd(iop_base);
16373 wbuf++;
16374 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016375
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016376 /*
16377 * Write EEPROM OEM name at words 22 to 29.
16378 */
16379 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16380 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16381 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016383 if (*charfields++) {
16384 word = cpu_to_le16(*wbuf);
16385 } else {
16386 word = *wbuf;
16387 }
16388 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16389 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16390 ASC_EEP_CMD_WRITE | addr);
16391 AdvWaitEEPCmd(iop_base);
16392 }
16393 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16394 AdvWaitEEPCmd(iop_base);
16395 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016396}
16397
16398/*
16399 * Write the EEPROM from 'cfg_buf'.
16400 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016401void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016402AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016403{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016404 ushort *wbuf;
16405 ushort *charfields;
16406 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016407
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016408 wbuf = (ushort *)cfg_buf;
16409 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16410 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016411
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016412 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16413 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016414
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016415 /*
16416 * Write EEPROM from word 0 to word 20.
16417 */
16418 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16419 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16420 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016421
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016422 if (*charfields++) {
16423 word = cpu_to_le16(*wbuf);
16424 } else {
16425 word = *wbuf;
16426 }
16427 chksum += *wbuf; /* Checksum is calculated from word values. */
16428 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16429 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16430 ASC_EEP_CMD_WRITE | addr);
16431 AdvWaitEEPCmd(iop_base);
16432 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016434
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016435 /*
16436 * Write EEPROM checksum at word 21.
16437 */
16438 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16439 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16440 AdvWaitEEPCmd(iop_base);
16441 wbuf++;
16442 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016443
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016444 /*
16445 * Write EEPROM OEM name at words 22 to 29.
16446 */
16447 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16448 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16449 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016450
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016451 if (*charfields++) {
16452 word = cpu_to_le16(*wbuf);
16453 } else {
16454 word = *wbuf;
16455 }
16456 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16457 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16458 ASC_EEP_CMD_WRITE | addr);
16459 AdvWaitEEPCmd(iop_base);
16460 }
16461 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16462 AdvWaitEEPCmd(iop_base);
16463 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016464}
16465
16466/* a_advlib.c */
16467/*
16468 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
16469 *
16470 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
16471 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
16472 * RISC to notify it a new command is ready to be executed.
16473 *
16474 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
16475 * set to SCSI_MAX_RETRY.
16476 *
16477 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
16478 * for DMA addresses or math operations are byte swapped to little-endian
16479 * order.
16480 *
16481 * Return:
16482 * ADV_SUCCESS(1) - The request was successfully queued.
16483 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
16484 * request completes.
16485 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
16486 * host IC error.
16487 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016488static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016489{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016490 ulong last_int_level;
16491 AdvPortAddr iop_base;
16492 ADV_DCNT req_size;
16493 ADV_PADDR req_paddr;
16494 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016495
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016496 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016497
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016498 /*
16499 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
16500 */
16501 if (scsiq->target_id > ADV_MAX_TID) {
16502 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
16503 scsiq->done_status = QD_WITH_ERROR;
16504 return ADV_ERROR;
16505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016506
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016507 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016508
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016509 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016510
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016511 /*
16512 * Allocate a carrier ensuring at least one carrier always
16513 * remains on the freelist and initialize fields.
16514 */
16515 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
16516 DvcLeaveCritical(last_int_level);
16517 return ADV_BUSY;
16518 }
16519 asc_dvc->carr_freelist = (ADV_CARR_T *)
16520 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
16521 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016522
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016523 /*
16524 * Set the carrier to be a stopper by setting 'next_vpa'
16525 * to the stopper value. The current stopper will be changed
16526 * below to point to the new stopper.
16527 */
16528 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016529
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016530 /*
16531 * Clear the ADV_SCSI_REQ_Q done flag.
16532 */
16533 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016535 req_size = sizeof(ADV_SCSI_REQ_Q);
16536 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
16537 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016538
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016539 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
16540 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016541
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016542 /* Wait for assertion before making little-endian */
16543 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016544
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016545 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
16546 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
16547 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016548
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016549 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
16550 /*
16551 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
16552 * order during initialization.
16553 */
16554 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016555
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016556 /*
16557 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
16558 * the microcode. The newly allocated stopper will become the new
16559 * stopper.
16560 */
16561 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016563 /*
16564 * Set the 'next_vpa' pointer for the old stopper to be the
16565 * physical address of the new stopper. The RISC can only
16566 * follow physical addresses.
16567 */
16568 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016569
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016570 /*
16571 * Set the host adapter stopper pointer to point to the new carrier.
16572 */
16573 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016575 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16576 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16577 /*
16578 * Tickle the RISC to tell it to read its Command Queue Head pointer.
16579 */
16580 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
16581 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16582 /*
16583 * Clear the tickle value. In the ASC-3550 the RISC flag
16584 * command 'clr_tickle_a' does not work unless the host
16585 * value is cleared.
16586 */
16587 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16588 ADV_TICKLE_NOP);
16589 }
16590 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16591 /*
16592 * Notify the RISC a carrier is ready by writing the physical
16593 * address of the new carrier stopper to the COMMA register.
16594 */
16595 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
16596 le32_to_cpu(new_carrp->carr_pa));
16597 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016598
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016599 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016600
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016601 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016602}
16603
16604/*
16605 * Reset SCSI Bus and purge all outstanding requests.
16606 *
16607 * Return Value:
16608 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
16609 * ADV_FALSE(0) - Microcode command failed.
16610 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
16611 * may be hung which requires driver recovery.
16612 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016613static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016614{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016615 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016616
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016617 /*
16618 * Send the SCSI Bus Reset idle start idle command which asserts
16619 * the SCSI Bus Reset signal.
16620 */
16621 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
16622 if (status != ADV_TRUE) {
16623 return status;
16624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016625
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016626 /*
16627 * Delay for the specified SCSI Bus Reset hold time.
16628 *
16629 * The hold time delay is done on the host because the RISC has no
16630 * microsecond accurate timer.
16631 */
16632 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016633
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016634 /*
16635 * Send the SCSI Bus Reset end idle command which de-asserts
16636 * the SCSI Bus Reset signal and purges any pending requests.
16637 */
16638 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
16639 if (status != ADV_TRUE) {
16640 return status;
16641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016643 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016644
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016645 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016646}
16647
16648/*
16649 * Reset chip and SCSI Bus.
16650 *
16651 * Return Value:
16652 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
16653 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
16654 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016655static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016656{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016657 int status;
16658 ushort wdtr_able, sdtr_able, tagqng_able;
16659 ushort ppr_able = 0;
16660 uchar tid, max_cmd[ADV_MAX_TID + 1];
16661 AdvPortAddr iop_base;
16662 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016663
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016664 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016665
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016666 /*
16667 * Save current per TID negotiated values.
16668 */
16669 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16670 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16671 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16672 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16673 }
16674 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16675 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16676 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16677 max_cmd[tid]);
16678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016679
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016680 /*
16681 * Force the AdvInitAsc3550/38C0800Driver() function to
16682 * perform a SCSI Bus Reset by clearing the BIOS signature word.
16683 * The initialization functions assumes a SCSI Bus Reset is not
16684 * needed if the BIOS signature word is present.
16685 */
16686 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
16687 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016688
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016689 /*
16690 * Stop chip and reset it.
16691 */
16692 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
16693 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
16694 DvcSleepMilliSecond(100);
16695 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
16696 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016697
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016698 /*
16699 * Reset Adv Library error code, if any, and try
16700 * re-initializing the chip.
16701 */
16702 asc_dvc->err_code = 0;
16703 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16704 status = AdvInitAsc38C1600Driver(asc_dvc);
16705 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16706 status = AdvInitAsc38C0800Driver(asc_dvc);
16707 } else {
16708 status = AdvInitAsc3550Driver(asc_dvc);
16709 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016710
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016711 /* Translate initialization return value to status value. */
16712 if (status == 0) {
16713 status = ADV_TRUE;
16714 } else {
16715 status = ADV_FALSE;
16716 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016717
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016718 /*
16719 * Restore the BIOS signature word.
16720 */
16721 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016722
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016723 /*
16724 * Restore per TID negotiated values.
16725 */
16726 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16727 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16728 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16729 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16730 }
16731 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16732 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16733 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16734 max_cmd[tid]);
16735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016736
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016737 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016738}
16739
16740/*
16741 * Adv Library Interrupt Service Routine
16742 *
16743 * This function is called by a driver's interrupt service routine.
16744 * The function disables and re-enables interrupts.
16745 *
16746 * When a microcode idle command is completed, the ADV_DVC_VAR
16747 * 'idle_cmd_done' field is set to ADV_TRUE.
16748 *
16749 * Note: AdvISR() can be called when interrupts are disabled or even
16750 * when there is no hardware interrupt condition present. It will
16751 * always check for completed idle commands and microcode requests.
16752 * This is an important feature that shouldn't be changed because it
16753 * allows commands to be completed from polling mode loops.
16754 *
16755 * Return:
16756 * ADV_TRUE(1) - interrupt was pending
16757 * ADV_FALSE(0) - no interrupt was pending
16758 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016759static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016760{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016761 AdvPortAddr iop_base;
16762 uchar int_stat;
16763 ushort target_bit;
16764 ADV_CARR_T *free_carrp;
16765 ADV_VADDR irq_next_vpa;
16766 int flags;
16767 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016768
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016769 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016770
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016771 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016772
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016773 /* Reading the register clears the interrupt. */
16774 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016775
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016776 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
16777 ADV_INTR_STATUS_INTRC)) == 0) {
16778 DvcLeaveCritical(flags);
16779 return ADV_FALSE;
16780 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016781
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016782 /*
16783 * Notify the driver of an asynchronous microcode condition by
16784 * calling the ADV_DVC_VAR.async_callback function. The function
16785 * is passed the microcode ASC_MC_INTRB_CODE byte value.
16786 */
16787 if (int_stat & ADV_INTR_STATUS_INTRB) {
16788 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016789
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016790 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016791
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016792 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16793 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16794 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
16795 asc_dvc->carr_pending_cnt != 0) {
16796 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16797 ADV_TICKLE_A);
16798 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16799 AdvWriteByteRegister(iop_base,
16800 IOPB_TICKLE,
16801 ADV_TICKLE_NOP);
16802 }
16803 }
16804 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016805
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016806 if (asc_dvc->async_callback != 0) {
16807 (*asc_dvc->async_callback) (asc_dvc, intrb_code);
16808 }
16809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016810
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016811 /*
16812 * Check if the IRQ stopper carrier contains a completed request.
16813 */
16814 while (((irq_next_vpa =
16815 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
16816 /*
16817 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
16818 * The RISC will have set 'areq_vpa' to a virtual address.
16819 *
16820 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
16821 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
16822 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
16823 * in AdvExeScsiQueue().
16824 */
16825 scsiq = (ADV_SCSI_REQ_Q *)
16826 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016827
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016828 /*
16829 * Request finished with good status and the queue was not
16830 * DMAed to host memory by the firmware. Set all status fields
16831 * to indicate good status.
16832 */
16833 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
16834 scsiq->done_status = QD_NO_ERROR;
16835 scsiq->host_status = scsiq->scsi_status = 0;
16836 scsiq->data_cnt = 0L;
16837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016838
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016839 /*
16840 * Advance the stopper pointer to the next carrier
16841 * ignoring the lower four bits. Free the previous
16842 * stopper carrier.
16843 */
16844 free_carrp = asc_dvc->irq_sp;
16845 asc_dvc->irq_sp = (ADV_CARR_T *)
16846 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016847
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016848 free_carrp->next_vpa =
16849 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
16850 asc_dvc->carr_freelist = free_carrp;
16851 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016852
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016853 ASC_ASSERT(scsiq != NULL);
16854 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016855
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016856 /*
16857 * Clear request microcode control flag.
16858 */
16859 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016860
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016861 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016862 * Notify the driver of the completed request by passing
16863 * the ADV_SCSI_REQ_Q pointer to its callback function.
16864 */
16865 scsiq->a_flag |= ADV_SCSIQ_DONE;
16866 (*asc_dvc->isr_callback) (asc_dvc, scsiq);
16867 /*
16868 * Note: After the driver callback function is called, 'scsiq'
16869 * can no longer be referenced.
16870 *
16871 * Fall through and continue processing other completed
16872 * requests...
16873 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016874
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016875 /*
16876 * Disable interrupts again in case the driver inadvertently
16877 * enabled interrupts in its callback function.
16878 *
16879 * The DvcEnterCritical() return value is ignored, because
16880 * the 'flags' saved when AdvISR() was first entered will be
16881 * used to restore the interrupt flag on exit.
16882 */
16883 (void)DvcEnterCritical();
16884 }
16885 DvcLeaveCritical(flags);
16886 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016887}
16888
16889/*
16890 * Send an idle command to the chip and wait for completion.
16891 *
16892 * Command completion is polled for once per microsecond.
16893 *
16894 * The function can be called from anywhere including an interrupt handler.
16895 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
16896 * functions to prevent reentrancy.
16897 *
16898 * Return Values:
16899 * ADV_TRUE - command completed successfully
16900 * ADV_FALSE - command failed
16901 * ADV_ERROR - command timed out
16902 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016903static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070016904AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016905 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016906{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016907 ulong last_int_level;
16908 int result;
16909 ADV_DCNT i, j;
16910 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016911
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016912 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016913
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016914 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016915
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016916 /*
16917 * Clear the idle command status which is set by the microcode
16918 * to a non-zero value to indicate when the command is completed.
16919 * The non-zero result is one of the IDLE_CMD_STATUS_* values
16920 * defined in a_advlib.h.
16921 */
16922 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016923
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016924 /*
16925 * Write the idle command value after the idle command parameter
16926 * has been written to avoid a race condition. If the order is not
16927 * followed, the microcode may process the idle command before the
16928 * parameters have been written to LRAM.
16929 */
16930 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
16931 cpu_to_le32(idle_cmd_parameter));
16932 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016933
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016934 /*
16935 * Tickle the RISC to tell it to process the idle command.
16936 */
16937 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
16938 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16939 /*
16940 * Clear the tickle value. In the ASC-3550 the RISC flag
16941 * command 'clr_tickle_b' does not work unless the host
16942 * value is cleared.
16943 */
16944 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
16945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016946
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016947 /* Wait for up to 100 millisecond for the idle command to timeout. */
16948 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
16949 /* Poll once each microsecond for command completion. */
16950 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
16951 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
16952 result);
16953 if (result != 0) {
16954 DvcLeaveCritical(last_int_level);
16955 return result;
16956 }
16957 DvcDelayMicroSecond(asc_dvc, (ushort)1);
16958 }
16959 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016960
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016961 ASC_ASSERT(0); /* The idle command should never timeout. */
16962 DvcLeaveCritical(last_int_level);
16963 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016964}
16965
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060016966static int __devinit
16967advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
16968{
16969 int req_cnt = 0;
16970 adv_req_t *reqp = NULL;
16971 int sg_cnt = 0;
16972 adv_sgblk_t *sgp;
16973 int warn_code, err_code;
16974
16975 /*
16976 * Allocate buffer carrier structures. The total size
16977 * is about 4 KB, so allocate all at once.
16978 */
16979 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
16980 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
16981
16982 if (!boardp->carrp)
16983 goto kmalloc_failed;
16984
16985 /*
16986 * Allocate up to 'max_host_qng' request structures for the Wide
16987 * board. The total size is about 16 KB, so allocate all at once.
16988 * If the allocation fails decrement and try again.
16989 */
16990 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
16991 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
16992
16993 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
16994 "bytes %lu\n", reqp, req_cnt,
16995 (ulong)sizeof(adv_req_t) * req_cnt);
16996
16997 if (reqp)
16998 break;
16999 }
17000
17001 if (!reqp)
17002 goto kmalloc_failed;
17003
17004 boardp->orig_reqp = reqp;
17005
17006 /*
17007 * Allocate up to ADV_TOT_SG_BLOCK request structures for
17008 * the Wide board. Each structure is about 136 bytes.
17009 */
17010 boardp->adv_sgblkp = NULL;
17011 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
17012 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
17013
17014 if (!sgp)
17015 break;
17016
17017 sgp->next_sgblkp = boardp->adv_sgblkp;
17018 boardp->adv_sgblkp = sgp;
17019
17020 }
17021
17022 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
17023 sg_cnt, sizeof(adv_sgblk_t),
17024 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
17025
17026 if (!boardp->adv_sgblkp)
17027 goto kmalloc_failed;
17028
17029 adv_dvc_varp->carrier_buf = boardp->carrp;
17030
17031 /*
17032 * Point 'adv_reqp' to the request structures and
17033 * link them together.
17034 */
17035 req_cnt--;
17036 reqp[req_cnt].next_reqp = NULL;
17037 for (; req_cnt > 0; req_cnt--) {
17038 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
17039 }
17040 boardp->adv_reqp = &reqp[0];
17041
17042 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17043 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
17044 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
17045 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17046 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
17047 "\n");
17048 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
17049 } else {
17050 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
17051 "\n");
17052 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
17053 }
17054 err_code = adv_dvc_varp->err_code;
17055
17056 if (warn_code || err_code) {
17057 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
17058 " error 0x%x\n", boardp->id, warn_code, err_code);
17059 }
17060
17061 goto exit;
17062
17063 kmalloc_failed:
17064 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
17065 "failed\n", boardp->id);
17066 err_code = ADV_ERROR;
17067 exit:
17068 return err_code;
17069}
17070
17071static void advansys_wide_free_mem(asc_board_t *boardp)
17072{
17073 kfree(boardp->carrp);
17074 boardp->carrp = NULL;
17075 kfree(boardp->orig_reqp);
17076 boardp->orig_reqp = boardp->adv_reqp = NULL;
17077 while (boardp->adv_sgblkp) {
17078 adv_sgblk_t *sgp = boardp->adv_sgblkp;
17079 boardp->adv_sgblkp = sgp->next_sgblkp;
17080 kfree(sgp);
17081 }
17082}
17083
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017084static struct Scsi_Host *__devinit
17085advansys_board_found(int iop, struct device *dev, int bus_type)
17086{
17087 struct Scsi_Host *shost;
17088 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
17089 asc_board_t *boardp;
17090 ASC_DVC_VAR *asc_dvc_varp = NULL;
17091 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017092 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017093 int warn_code, err_code;
17094 int ret;
17095
17096 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017097 * Register the adapter, get its configuration, and
17098 * initialize it.
17099 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017100 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
17101 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017102 if (!shost)
17103 return NULL;
17104
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017105 /* Initialize private per board data */
17106 boardp = ASC_BOARDP(shost);
17107 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017108 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017109 spin_lock_init(&boardp->lock);
17110
17111 /*
17112 * Handle both narrow and wide boards.
17113 *
17114 * If a Wide board was detected, set the board structure
17115 * wide board flag. Set-up the board structure based on
17116 * the board type.
17117 */
17118#ifdef CONFIG_PCI
17119 if (bus_type == ASC_IS_PCI &&
17120 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17121 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17122 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17123 boardp->flags |= ASC_IS_WIDE_BOARD;
17124 }
17125#endif /* CONFIG_PCI */
17126
17127 if (ASC_NARROW_BOARD(boardp)) {
17128 ASC_DBG(1, "advansys_board_found: narrow board\n");
17129 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17130 asc_dvc_varp->bus_type = bus_type;
17131 asc_dvc_varp->drv_ptr = boardp;
17132 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17133 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17134 asc_dvc_varp->iop_base = iop;
17135 asc_dvc_varp->isr_callback = asc_isr_callback;
17136 } else {
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017137#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017138 ASC_DBG(1, "advansys_board_found: wide board\n");
17139 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17140 adv_dvc_varp->drv_ptr = boardp;
17141 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
17142 adv_dvc_varp->isr_callback = adv_isr_callback;
17143 adv_dvc_varp->async_callback = adv_async_callback;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017144 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17145 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17146 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17147 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17148 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17149 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17150 } else {
17151 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17152 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17153 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017154
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017155 boardp->asc_n_io_port = pci_resource_len(pdev, 1);
17156 boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
17157 boardp->asc_n_io_port);
17158 if (!boardp->ioremap_addr) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017159 ASC_PRINT3
17160 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017161 boardp->id, pci_resource_start(pdev, 1),
17162 boardp->asc_n_io_port);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017163 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017164 }
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017165 adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr
Matthew Wilcox71f36112007-07-30 08:04:53 -060017166 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017167 adv_dvc_varp->iop_base);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017168
17169 /*
17170 * Even though it isn't used to access wide boards, other
17171 * than for the debug line below, save I/O Port address so
17172 * that it can be reported.
17173 */
17174 boardp->ioport = iop;
17175
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017176 ASC_DBG2(1, "advansys_board_found: iopb_chip_id_1 0x%x, "
17177 "iopw_chip_id_0 0x%x\n", (ushort)inp(iop + 1),
17178 (ushort)inpw(iop));
17179#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017180 }
17181
17182#ifdef CONFIG_PROC_FS
17183 /*
17184 * Allocate buffer for printing information from
17185 * /proc/scsi/advansys/[0...].
17186 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017187 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
17188 if (!boardp->prtbuf) {
17189 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
17190 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
17191 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017192 }
17193#endif /* CONFIG_PROC_FS */
17194
17195 if (ASC_NARROW_BOARD(boardp)) {
17196 asc_dvc_varp->cfg->dev = dev;
17197 /*
17198 * Set the board bus type and PCI IRQ before
17199 * calling AscInitGetConfig().
17200 */
17201 switch (asc_dvc_varp->bus_type) {
17202#ifdef CONFIG_ISA
17203 case ASC_IS_ISA:
17204 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017205 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017206 break;
17207 case ASC_IS_VL:
17208 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017209 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017210 break;
17211 case ASC_IS_EISA:
17212 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017213 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017214 break;
17215#endif /* CONFIG_ISA */
17216#ifdef CONFIG_PCI
17217 case ASC_IS_PCI:
17218 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
17219 asc_dvc_varp->cfg->pci_slot_info =
17220 ASC_PCI_MKID(pdev->bus->number,
17221 PCI_SLOT(pdev->devfn),
17222 PCI_FUNC(pdev->devfn));
17223 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017224 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017225 break;
17226#endif /* CONFIG_PCI */
17227 default:
17228 ASC_PRINT2
17229 ("advansys_board_found: board %d: unknown adapter type: %d\n",
17230 boardp->id, asc_dvc_varp->bus_type);
17231 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017232 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017233 break;
17234 }
17235 } else {
17236 adv_dvc_varp->cfg->dev = dev;
17237 /*
17238 * For Wide boards set PCI information before calling
17239 * AdvInitGetConfig().
17240 */
17241#ifdef CONFIG_PCI
17242 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
17243 adv_dvc_varp->cfg->pci_slot_info =
17244 ASC_PCI_MKID(pdev->bus->number,
17245 PCI_SLOT(pdev->devfn),
17246 PCI_FUNC(pdev->devfn));
17247 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017248 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017249#endif /* CONFIG_PCI */
17250 }
17251
17252 /*
17253 * Read the board configuration.
17254 */
17255 if (ASC_NARROW_BOARD(boardp)) {
17256 /*
17257 * NOTE: AscInitGetConfig() may change the board's
17258 * bus_type value. The bus_type value should no
17259 * longer be used. If the bus_type field must be
17260 * referenced only use the bit-wise AND operator "&".
17261 */
17262 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
17263 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
17264 case 0: /* No error */
17265 break;
17266 case ASC_WARN_IO_PORT_ROTATE:
17267 ASC_PRINT1
17268 ("AscInitGetConfig: board %d: I/O port address modified\n",
17269 boardp->id);
17270 break;
17271 case ASC_WARN_AUTO_CONFIG:
17272 ASC_PRINT1
17273 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
17274 boardp->id);
17275 break;
17276 case ASC_WARN_EEPROM_CHKSUM:
17277 ASC_PRINT1
17278 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
17279 boardp->id);
17280 break;
17281 case ASC_WARN_IRQ_MODIFIED:
17282 ASC_PRINT1
17283 ("AscInitGetConfig: board %d: IRQ modified\n",
17284 boardp->id);
17285 break;
17286 case ASC_WARN_CMD_QNG_CONFLICT:
17287 ASC_PRINT1
17288 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
17289 boardp->id);
17290 break;
17291 default:
17292 ASC_PRINT2
17293 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
17294 boardp->id, ret);
17295 break;
17296 }
17297 if ((err_code = asc_dvc_varp->err_code) != 0) {
17298 ASC_PRINT3
17299 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17300 boardp->id,
17301 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
17302 }
17303 } else {
17304 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
17305 if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
17306 ASC_PRINT2
17307 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
17308 boardp->id, ret);
17309 }
17310 if ((err_code = adv_dvc_varp->err_code) != 0) {
17311 ASC_PRINT2
17312 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
17313 boardp->id, adv_dvc_varp->err_code);
17314 }
17315 }
17316
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017317 if (err_code != 0)
17318 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017319
17320 /*
17321 * Save the EEPROM configuration so that it can be displayed
17322 * from /proc/scsi/advansys/[0...].
17323 */
17324 if (ASC_NARROW_BOARD(boardp)) {
17325
17326 ASCEEP_CONFIG *ep;
17327
17328 /*
17329 * Set the adapter's target id bit in the 'init_tidmask' field.
17330 */
17331 boardp->init_tidmask |=
17332 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
17333
17334 /*
17335 * Save EEPROM settings for the board.
17336 */
17337 ep = &boardp->eep_config.asc_eep;
17338
17339 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
17340 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
17341 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
17342 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
17343 ep->start_motor = asc_dvc_varp->start_motor;
17344 ep->cntl = asc_dvc_varp->dvc_cntl;
17345 ep->no_scam = asc_dvc_varp->no_scam;
17346 ep->max_total_qng = asc_dvc_varp->max_total_qng;
17347 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
17348 /* 'max_tag_qng' is set to the same value for every device. */
17349 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
17350 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
17351 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
17352 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
17353 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
17354 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
17355 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
17356
17357 /*
17358 * Modify board configuration.
17359 */
17360 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
17361 switch (ret = AscInitSetConfig(asc_dvc_varp)) {
17362 case 0: /* No error. */
17363 break;
17364 case ASC_WARN_IO_PORT_ROTATE:
17365 ASC_PRINT1
17366 ("AscInitSetConfig: board %d: I/O port address modified\n",
17367 boardp->id);
17368 break;
17369 case ASC_WARN_AUTO_CONFIG:
17370 ASC_PRINT1
17371 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
17372 boardp->id);
17373 break;
17374 case ASC_WARN_EEPROM_CHKSUM:
17375 ASC_PRINT1
17376 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
17377 boardp->id);
17378 break;
17379 case ASC_WARN_IRQ_MODIFIED:
17380 ASC_PRINT1
17381 ("AscInitSetConfig: board %d: IRQ modified\n",
17382 boardp->id);
17383 break;
17384 case ASC_WARN_CMD_QNG_CONFLICT:
17385 ASC_PRINT1
17386 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
17387 boardp->id);
17388 break;
17389 default:
17390 ASC_PRINT2
17391 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
17392 boardp->id, ret);
17393 break;
17394 }
17395 if (asc_dvc_varp->err_code != 0) {
17396 ASC_PRINT3
17397 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17398 boardp->id,
17399 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017400 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017401 }
17402
17403 /*
17404 * Finish initializing the 'Scsi_Host' structure.
17405 */
17406 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
17407 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
17408 shost->irq = asc_dvc_varp->irq_no;
17409 }
17410 } else {
17411 ADVEEP_3550_CONFIG *ep_3550;
17412 ADVEEP_38C0800_CONFIG *ep_38C0800;
17413 ADVEEP_38C1600_CONFIG *ep_38C1600;
17414
17415 /*
17416 * Save Wide EEP Configuration Information.
17417 */
17418 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17419 ep_3550 = &boardp->eep_config.adv_3550_eep;
17420
17421 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
17422 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
17423 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17424 ep_3550->termination = adv_dvc_varp->cfg->termination;
17425 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
17426 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
17427 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
17428 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
17429 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
17430 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
17431 ep_3550->start_motor = adv_dvc_varp->start_motor;
17432 ep_3550->scsi_reset_delay =
17433 adv_dvc_varp->scsi_reset_wait;
17434 ep_3550->serial_number_word1 =
17435 adv_dvc_varp->cfg->serial1;
17436 ep_3550->serial_number_word2 =
17437 adv_dvc_varp->cfg->serial2;
17438 ep_3550->serial_number_word3 =
17439 adv_dvc_varp->cfg->serial3;
17440 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17441 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
17442
17443 ep_38C0800->adapter_scsi_id =
17444 adv_dvc_varp->chip_scsi_id;
17445 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
17446 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17447 ep_38C0800->termination_lvd =
17448 adv_dvc_varp->cfg->termination;
17449 ep_38C0800->disc_enable =
17450 adv_dvc_varp->cfg->disc_enable;
17451 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
17452 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
17453 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17454 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17455 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17456 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17457 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17458 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17459 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
17460 ep_38C0800->scsi_reset_delay =
17461 adv_dvc_varp->scsi_reset_wait;
17462 ep_38C0800->serial_number_word1 =
17463 adv_dvc_varp->cfg->serial1;
17464 ep_38C0800->serial_number_word2 =
17465 adv_dvc_varp->cfg->serial2;
17466 ep_38C0800->serial_number_word3 =
17467 adv_dvc_varp->cfg->serial3;
17468 } else {
17469 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
17470
17471 ep_38C1600->adapter_scsi_id =
17472 adv_dvc_varp->chip_scsi_id;
17473 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
17474 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17475 ep_38C1600->termination_lvd =
17476 adv_dvc_varp->cfg->termination;
17477 ep_38C1600->disc_enable =
17478 adv_dvc_varp->cfg->disc_enable;
17479 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
17480 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
17481 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17482 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17483 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17484 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17485 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17486 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17487 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
17488 ep_38C1600->scsi_reset_delay =
17489 adv_dvc_varp->scsi_reset_wait;
17490 ep_38C1600->serial_number_word1 =
17491 adv_dvc_varp->cfg->serial1;
17492 ep_38C1600->serial_number_word2 =
17493 adv_dvc_varp->cfg->serial2;
17494 ep_38C1600->serial_number_word3 =
17495 adv_dvc_varp->cfg->serial3;
17496 }
17497
17498 /*
17499 * Set the adapter's target id bit in the 'init_tidmask' field.
17500 */
17501 boardp->init_tidmask |=
17502 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017503 }
17504
17505 /*
17506 * Channels are numbered beginning with 0. For AdvanSys one host
17507 * structure supports one channel. Multi-channel boards have a
17508 * separate host structure for each channel.
17509 */
17510 shost->max_channel = 0;
17511 if (ASC_NARROW_BOARD(boardp)) {
17512 shost->max_id = ASC_MAX_TID + 1;
17513 shost->max_lun = ASC_MAX_LUN + 1;
17514
17515 shost->io_port = asc_dvc_varp->iop_base;
17516 boardp->asc_n_io_port = ASC_IOADR_GAP;
17517 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
17518
17519 /* Set maximum number of queues the adapter can handle. */
17520 shost->can_queue = asc_dvc_varp->max_total_qng;
17521 } else {
17522 shost->max_id = ADV_MAX_TID + 1;
17523 shost->max_lun = ADV_MAX_LUN + 1;
17524
17525 /*
17526 * Save the I/O Port address and length even though
17527 * I/O ports are not used to access Wide boards.
17528 * Instead the Wide boards are accessed with
17529 * PCI Memory Mapped I/O.
17530 */
17531 shost->io_port = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017532
17533 shost->this_id = adv_dvc_varp->chip_scsi_id;
17534
17535 /* Set maximum number of queues the adapter can handle. */
17536 shost->can_queue = adv_dvc_varp->max_host_qng;
17537 }
17538
17539 /*
17540 * 'n_io_port' currently is one byte.
17541 *
17542 * Set a value to 'n_io_port', but never referenced it because
17543 * it may be truncated.
17544 */
17545 shost->n_io_port = boardp->asc_n_io_port <= 255 ?
17546 boardp->asc_n_io_port : 255;
17547
17548 /*
17549 * Following v1.3.89, 'cmd_per_lun' is no longer needed
17550 * and should be set to zero.
17551 *
17552 * But because of a bug introduced in v1.3.89 if the driver is
17553 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
17554 * SCSI function 'allocate_device' will panic. To allow the driver
17555 * to work as a module in these kernels set 'cmd_per_lun' to 1.
17556 *
17557 * Note: This is wrong. cmd_per_lun should be set to the depth
17558 * you want on untagged devices always.
17559 #ifdef MODULE
17560 */
17561 shost->cmd_per_lun = 1;
17562/* #else
17563 shost->cmd_per_lun = 0;
17564#endif */
17565
17566 /*
17567 * Set the maximum number of scatter-gather elements the
17568 * adapter can handle.
17569 */
17570 if (ASC_NARROW_BOARD(boardp)) {
17571 /*
17572 * Allow two commands with 'sg_tablesize' scatter-gather
17573 * elements to be executed simultaneously. This value is
17574 * the theoretical hardware limit. It may be decreased
17575 * below.
17576 */
17577 shost->sg_tablesize =
17578 (((asc_dvc_varp->max_total_qng - 2) / 2) *
17579 ASC_SG_LIST_PER_Q) + 1;
17580 } else {
17581 shost->sg_tablesize = ADV_MAX_SG_LIST;
17582 }
17583
17584 /*
17585 * The value of 'sg_tablesize' can not exceed the SCSI
17586 * mid-level driver definition of SG_ALL. SG_ALL also
17587 * must not be exceeded, because it is used to define the
17588 * size of the scatter-gather table in 'struct asc_sg_head'.
17589 */
17590 if (shost->sg_tablesize > SG_ALL) {
17591 shost->sg_tablesize = SG_ALL;
17592 }
17593
17594 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
17595
17596 /* BIOS start address. */
17597 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017598 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
17599 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017600 } else {
17601 /*
17602 * Fill-in BIOS board variables. The Wide BIOS saves
17603 * information in LRAM that is used by the driver.
17604 */
17605 AdvReadWordLram(adv_dvc_varp->iop_base,
17606 BIOS_SIGNATURE, boardp->bios_signature);
17607 AdvReadWordLram(adv_dvc_varp->iop_base,
17608 BIOS_VERSION, boardp->bios_version);
17609 AdvReadWordLram(adv_dvc_varp->iop_base,
17610 BIOS_CODESEG, boardp->bios_codeseg);
17611 AdvReadWordLram(adv_dvc_varp->iop_base,
17612 BIOS_CODELEN, boardp->bios_codelen);
17613
17614 ASC_DBG2(1,
17615 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
17616 boardp->bios_signature, boardp->bios_version);
17617
17618 ASC_DBG2(1,
17619 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
17620 boardp->bios_codeseg, boardp->bios_codelen);
17621
17622 /*
17623 * If the BIOS saved a valid signature, then fill in
17624 * the BIOS code segment base address.
17625 */
17626 if (boardp->bios_signature == 0x55AA) {
17627 /*
17628 * Convert x86 realmode code segment to a linear
17629 * address by shifting left 4.
17630 */
17631 shost->base = ((ulong)boardp->bios_codeseg << 4);
17632 } else {
17633 shost->base = 0;
17634 }
17635 }
17636
17637 /*
17638 * Register Board Resources - I/O Port, DMA, IRQ
17639 */
17640
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017641 /* Register DMA Channel for Narrow boards. */
17642 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
17643#ifdef CONFIG_ISA
17644 if (ASC_NARROW_BOARD(boardp)) {
17645 /* Register DMA channel for ISA bus. */
17646 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
17647 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017648 ret = request_dma(shost->dma_channel, "advansys");
17649 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017650 ASC_PRINT3
17651 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
17652 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017653 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017654 }
17655 AscEnableIsaDma(shost->dma_channel);
17656 }
17657 }
17658#endif /* CONFIG_ISA */
17659
17660 /* Register IRQ Number. */
17661 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017662
17663 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
17664 "advansys", shost);
17665
17666 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017667 if (ret == -EBUSY) {
17668 ASC_PRINT2
17669 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
17670 boardp->id, shost->irq);
17671 } else if (ret == -EINVAL) {
17672 ASC_PRINT2
17673 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
17674 boardp->id, shost->irq);
17675 } else {
17676 ASC_PRINT3
17677 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
17678 boardp->id, shost->irq, ret);
17679 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017680 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017681 }
17682
17683 /*
17684 * Initialize board RISC chip and enable interrupts.
17685 */
17686 if (ASC_NARROW_BOARD(boardp)) {
17687 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
17688 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
17689 err_code = asc_dvc_varp->err_code;
17690
17691 if (warn_code || err_code) {
17692 ASC_PRINT4
17693 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
17694 boardp->id,
17695 asc_dvc_varp->init_state, warn_code, err_code);
17696 }
17697 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017698 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017699 }
17700
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017701 if (err_code != 0)
17702 goto err_free_wide_mem;
17703
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017704 ASC_DBG_PRT_SCSI_HOST(2, shost);
17705
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017706 ret = scsi_add_host(shost, dev);
17707 if (ret)
17708 goto err_free_wide_mem;
17709
17710 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017711 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017712
17713 err_free_wide_mem:
17714 advansys_wide_free_mem(boardp);
17715 free_irq(shost->irq, shost);
17716 err_free_dma:
17717 if (shost->dma_channel != NO_ISA_DMA)
17718 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017719 err_free_proc:
17720 kfree(boardp->prtbuf);
17721 err_unmap:
17722 if (boardp->ioremap_addr)
17723 iounmap(boardp->ioremap_addr);
17724 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017725 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017726 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017727}
17728
17729/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017730 * advansys_release()
17731 *
17732 * Release resources allocated for a single AdvanSys adapter.
17733 */
17734static int advansys_release(struct Scsi_Host *shost)
17735{
17736 asc_board_t *boardp;
17737
17738 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017739 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017740 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017741 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017742 if (shost->dma_channel != NO_ISA_DMA) {
17743 ASC_DBG(1, "advansys_release: free_dma()\n");
17744 free_dma(shost->dma_channel);
17745 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017746 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017747 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017748 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017749 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017750 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017751 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017752 ASC_DBG(1, "advansys_release: end\n");
17753 return 0;
17754}
17755
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017756static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
17757 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
17758 0x0210, 0x0230, 0x0250, 0x0330
17759};
17760
17761static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
17762{
17763 PortAddr iop_base = _asc_def_iop_base[id];
17764 struct Scsi_Host *shost;
17765
17766 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017767 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
17768 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017769 return -ENODEV;
17770 }
17771 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017772 if (!AscFindSignature(iop_base))
17773 goto nodev;
17774 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
17775 goto nodev;
17776
17777 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017778 if (!shost)
17779 goto nodev;
17780
17781 dev_set_drvdata(dev, shost);
17782 return 0;
17783
17784 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060017785 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017786 return -ENODEV;
17787}
17788
17789static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
17790{
Matthew Wilcox71f36112007-07-30 08:04:53 -060017791 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017792 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060017793 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017794 return 0;
17795}
17796
17797static struct isa_driver advansys_isa_driver = {
17798 .probe = advansys_isa_probe,
17799 .remove = __devexit_p(advansys_isa_remove),
17800 .driver = {
17801 .owner = THIS_MODULE,
17802 .name = "advansys",
17803 },
17804};
17805
17806static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
17807{
17808 PortAddr iop_base = _asc_def_iop_base[id];
17809 struct Scsi_Host *shost;
17810
17811 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017812 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
17813 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017814 return -ENODEV;
17815 }
17816 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017817 if (!AscFindSignature(iop_base))
17818 goto nodev;
17819 /*
17820 * I don't think this condition can actually happen, but the old
17821 * driver did it, and the chances of finding a VLB setup in 2007
17822 * to do testing with is slight to none.
17823 */
17824 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
17825 goto nodev;
17826
17827 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017828 if (!shost)
17829 goto nodev;
17830
17831 dev_set_drvdata(dev, shost);
17832 return 0;
17833
17834 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060017835 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017836 return -ENODEV;
17837}
17838
17839static struct isa_driver advansys_vlb_driver = {
17840 .probe = advansys_vlb_probe,
17841 .remove = __devexit_p(advansys_isa_remove),
17842 .driver = {
17843 .owner = THIS_MODULE,
17844 .name = "advansys",
17845 },
17846};
17847
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017848static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
17849 { "ABP7401" },
17850 { "ABP7501" },
17851 { "" }
17852};
17853
17854MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
17855
17856/*
17857 * EISA is a little more tricky than PCI; each EISA device may have two
17858 * channels, and this driver is written to make each channel its own Scsi_Host
17859 */
17860struct eisa_scsi_data {
17861 struct Scsi_Host *host[2];
17862};
17863
17864static int __devinit advansys_eisa_probe(struct device *dev)
17865{
17866 int i, ioport;
17867 int err;
17868 struct eisa_device *edev = to_eisa_device(dev);
17869 struct eisa_scsi_data *data;
17870
17871 err = -ENOMEM;
17872 data = kzalloc(sizeof(*data), GFP_KERNEL);
17873 if (!data)
17874 goto fail;
17875 ioport = edev->base_addr + 0xc30;
17876
17877 err = -ENODEV;
17878 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017879 if (!request_region(ioport, ASC_IOADR_GAP, "advansys")) {
17880 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
17881 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017882 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017883 }
17884 if (!AscFindSignature(ioport)) {
17885 release_region(ioport, ASC_IOADR_GAP);
17886 continue;
17887 }
17888
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017889 /*
17890 * I don't know why we need to do this for EISA chips, but
17891 * not for any others. It looks to be equivalent to
17892 * AscGetChipCfgMsw, but I may have overlooked something,
17893 * so I'm not converting it until I get an EISA board to
17894 * test with.
17895 */
17896 inw(ioport + 4);
17897 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017898 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017899 err = 0;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017900 } else {
17901 release_region(ioport, ASC_IOADR_GAP);
17902 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017903 }
17904
17905 if (err) {
17906 kfree(data);
17907 } else {
17908 dev_set_drvdata(dev, data);
17909 }
17910
17911 fail:
17912 return err;
17913}
17914
17915static __devexit int advansys_eisa_remove(struct device *dev)
17916{
17917 int i;
17918 struct eisa_scsi_data *data = dev_get_drvdata(dev);
17919
17920 for (i = 0; i < 2; i++) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017921 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017922 struct Scsi_Host *shost = data->host[i];
17923 if (!shost)
17924 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017925 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017926 advansys_release(shost);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017927 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017928 }
17929
17930 kfree(data);
17931 return 0;
17932}
17933
17934static struct eisa_driver advansys_eisa_driver = {
17935 .id_table = advansys_eisa_table,
17936 .driver = {
17937 .name = "advansys",
17938 .probe = advansys_eisa_probe,
17939 .remove = __devexit_p(advansys_eisa_remove),
17940 }
17941};
17942
Dave Jones2672ea82006-08-02 17:11:49 -040017943/* PCI Devices supported by this driver */
17944static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017945 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
17946 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17947 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
17948 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17949 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
17950 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17951 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
17952 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17953 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
17954 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17955 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
17956 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17957 {}
Dave Jones2672ea82006-08-02 17:11:49 -040017958};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017959
Dave Jones2672ea82006-08-02 17:11:49 -040017960MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017961
Matthew Wilcox9649af32007-07-26 21:51:47 -060017962static void __devinit advansys_set_latency(struct pci_dev *pdev)
17963{
17964 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
17965 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
17966 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
17967 } else {
17968 u8 latency;
17969 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
17970 if (latency < 0x20)
17971 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
17972 }
17973}
17974
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017975static int __devinit
17976advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
17977{
17978 int err, ioport;
17979 struct Scsi_Host *shost;
17980
17981 err = pci_enable_device(pdev);
17982 if (err)
17983 goto fail;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017984 err = pci_request_regions(pdev, "advansys");
17985 if (err)
17986 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060017987 pci_set_master(pdev);
17988 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017989
17990 if (pci_resource_len(pdev, 0) == 0)
17991 goto nodev;
17992
17993 ioport = pci_resource_start(pdev, 0);
17994 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
17995
17996 if (!shost)
17997 goto nodev;
17998
17999 pci_set_drvdata(pdev, shost);
18000 return 0;
18001
18002 nodev:
18003 err = -ENODEV;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018004 pci_release_regions(pdev);
18005 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018006 pci_disable_device(pdev);
18007 fail:
18008 return err;
18009}
18010
18011static void __devexit advansys_pci_remove(struct pci_dev *pdev)
18012{
18013 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060018014 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018015 pci_disable_device(pdev);
18016}
18017
18018static struct pci_driver advansys_pci_driver = {
18019 .name = "advansys",
18020 .id_table = advansys_pci_tbl,
18021 .probe = advansys_pci_probe,
18022 .remove = __devexit_p(advansys_pci_remove),
18023};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018024
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018025static int __init advansys_init(void)
18026{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018027 int error;
18028
18029 error = isa_register_driver(&advansys_isa_driver,
18030 ASC_IOADR_TABLE_MAX_IX);
18031 if (error)
18032 goto fail;
18033
18034 error = isa_register_driver(&advansys_vlb_driver,
18035 ASC_IOADR_TABLE_MAX_IX);
18036 if (error)
18037 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018038
18039 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018040 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018041 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018042
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018043 error = pci_register_driver(&advansys_pci_driver);
18044 if (error)
18045 goto unregister_eisa;
18046
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018047 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018048
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018049 unregister_eisa:
18050 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018051 unregister_vlb:
18052 isa_unregister_driver(&advansys_vlb_driver);
18053 unregister_isa:
18054 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018055 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018056 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018057}
18058
18059static void __exit advansys_exit(void)
18060{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018061 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018062 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018063 isa_unregister_driver(&advansys_vlb_driver);
18064 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018065}
18066
18067module_init(advansys_init);
18068module_exit(advansys_exit);
18069
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018070MODULE_LICENSE("GPL");