blob: 19c2d19f254cfb59a08e397334449bedacfe6d47 [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
858#define ASC_DVCLIB_CALL_DONE (1)
859#define ASC_DVCLIB_CALL_FAILED (0)
860#define ASC_DVCLIB_CALL_ERROR (-1)
861
Dave Jones2672ea82006-08-02 17:11:49 -0400862#define PCI_VENDOR_ID_ASP 0x10cd
863#define PCI_DEVICE_ID_ASP_1200A 0x1100
864#define PCI_DEVICE_ID_ASP_ABP940 0x1200
865#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
866#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
867#define PCI_DEVICE_ID_38C0800_REV1 0x2500
868#define PCI_DEVICE_ID_38C1600_REV1 0x2700
869
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870/*
871 * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
872 * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
873 * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
874 * SRB structure.
875 */
876#define CC_VERY_LONG_SG_LIST 0
877#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
878
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400879#define PortAddr unsigned short /* port address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880#define inp(port) inb(port)
881#define outp(port, byte) outb((byte), (port))
882
883#define inpw(port) inw(port)
884#define outpw(port, word) outw((word), (port))
885
886#define ASC_MAX_SG_QUEUE 7
887#define ASC_MAX_SG_LIST 255
888
889#define ASC_CS_TYPE unsigned short
890
891#define ASC_IS_ISA (0x0001)
892#define ASC_IS_ISAPNP (0x0081)
893#define ASC_IS_EISA (0x0002)
894#define ASC_IS_PCI (0x0004)
895#define ASC_IS_PCI_ULTRA (0x0104)
896#define ASC_IS_PCMCIA (0x0008)
897#define ASC_IS_MCA (0x0020)
898#define ASC_IS_VL (0x0040)
899#define ASC_ISA_PNP_PORT_ADDR (0x279)
900#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
901#define ASC_IS_WIDESCSI_16 (0x0100)
902#define ASC_IS_WIDESCSI_32 (0x0200)
903#define ASC_IS_BIG_ENDIAN (0x8000)
904#define ASC_CHIP_MIN_VER_VL (0x01)
905#define ASC_CHIP_MAX_VER_VL (0x07)
906#define ASC_CHIP_MIN_VER_PCI (0x09)
907#define ASC_CHIP_MAX_VER_PCI (0x0F)
908#define ASC_CHIP_VER_PCI_BIT (0x08)
909#define ASC_CHIP_MIN_VER_ISA (0x11)
910#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
911#define ASC_CHIP_MAX_VER_ISA (0x27)
912#define ASC_CHIP_VER_ISA_BIT (0x30)
913#define ASC_CHIP_VER_ISAPNP_BIT (0x20)
914#define ASC_CHIP_VER_ASYN_BUG (0x21)
915#define ASC_CHIP_VER_PCI 0x08
916#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02)
917#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03)
918#define ASC_CHIP_MIN_VER_EISA (0x41)
919#define ASC_CHIP_MAX_VER_EISA (0x47)
920#define ASC_CHIP_VER_EISA_BIT (0x40)
921#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
922#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21
923#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A
924#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL)
925#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
926#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL)
927#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
928#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL)
929#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
930#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
931#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
932
933#define ASC_SCSI_ID_BITS 3
934#define ASC_SCSI_TIX_TYPE uchar
935#define ASC_ALL_DEVICE_BIT_SET 0xFF
936#define ASC_SCSI_BIT_ID_TYPE uchar
937#define ASC_MAX_TID 7
938#define ASC_MAX_LUN 7
939#define ASC_SCSI_WIDTH_BIT_SET 0xFF
940#define ASC_MAX_SENSE_LEN 32
941#define ASC_MIN_SENSE_LEN 14
942#define ASC_MAX_CDB_LEN 12
943#define ASC_SCSI_RESET_HOLD_TIME_US 60
944
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945/*
946 * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
947 * and CmdDt (Command Support Data) field bit definitions.
948 */
949#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3
950#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2
951#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1
952#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0
953
954#define ASC_SCSIDIR_NOCHK 0x00
955#define ASC_SCSIDIR_T2H 0x08
956#define ASC_SCSIDIR_H2T 0x10
957#define ASC_SCSIDIR_NODATA 0x18
958#define SCSI_ASC_NOMEDIA 0x3A
959#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
960#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
961#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
962#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963#define MS_SDTR_LEN 0x03
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964#define MS_WDTR_LEN 0x02
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
966#define ASC_SG_LIST_PER_Q 7
967#define QS_FREE 0x00
968#define QS_READY 0x01
969#define QS_DISC1 0x02
970#define QS_DISC2 0x04
971#define QS_BUSY 0x08
972#define QS_ABORTED 0x40
973#define QS_DONE 0x80
974#define QC_NO_CALLBACK 0x01
975#define QC_SG_SWAP_QUEUE 0x02
976#define QC_SG_HEAD 0x04
977#define QC_DATA_IN 0x08
978#define QC_DATA_OUT 0x10
979#define QC_URGENT 0x20
980#define QC_MSG_OUT 0x40
981#define QC_REQ_SENSE 0x80
982#define QCSG_SG_XFER_LIST 0x02
983#define QCSG_SG_XFER_MORE 0x04
984#define QCSG_SG_XFER_END 0x08
985#define QD_IN_PROGRESS 0x00
986#define QD_NO_ERROR 0x01
987#define QD_ABORTED_BY_HOST 0x02
988#define QD_WITH_ERROR 0x04
989#define QD_INVALID_REQUEST 0x80
990#define QD_INVALID_HOST_NUM 0x81
991#define QD_INVALID_DEVICE 0x82
992#define QD_ERR_INTERNAL 0xFF
993#define QHSTA_NO_ERROR 0x00
994#define QHSTA_M_SEL_TIMEOUT 0x11
995#define QHSTA_M_DATA_OVER_RUN 0x12
996#define QHSTA_M_DATA_UNDER_RUN 0x12
997#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
998#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
999#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
1000#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
1001#define QHSTA_D_HOST_ABORT_FAILED 0x23
1002#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
1003#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
1004#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
1005#define QHSTA_M_WTM_TIMEOUT 0x41
1006#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
1007#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
1008#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
1009#define QHSTA_M_TARGET_STATUS_BUSY 0x45
1010#define QHSTA_M_BAD_TAG_CODE 0x46
1011#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
1012#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
1013#define QHSTA_D_LRAM_CMP_ERROR 0x81
1014#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
1015#define ASC_FLAG_SCSIQ_REQ 0x01
1016#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02
1017#define ASC_FLAG_BIOS_ASYNC_IO 0x04
1018#define ASC_FLAG_SRB_LINEAR_ADDR 0x08
1019#define ASC_FLAG_WIN16 0x10
1020#define ASC_FLAG_WIN32 0x20
1021#define ASC_FLAG_ISA_OVER_16MB 0x40
1022#define ASC_FLAG_DOS_VM_CALLBACK 0x80
1023#define ASC_TAG_FLAG_EXTRA_BYTES 0x10
1024#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04
1025#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
1026#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
1027#define ASC_SCSIQ_CPY_BEG 4
1028#define ASC_SCSIQ_SGHD_CPY_BEG 2
1029#define ASC_SCSIQ_B_FWD 0
1030#define ASC_SCSIQ_B_BWD 1
1031#define ASC_SCSIQ_B_STATUS 2
1032#define ASC_SCSIQ_B_QNO 3
1033#define ASC_SCSIQ_B_CNTL 4
1034#define ASC_SCSIQ_B_SG_QUEUE_CNT 5
1035#define ASC_SCSIQ_D_DATA_ADDR 8
1036#define ASC_SCSIQ_D_DATA_CNT 12
1037#define ASC_SCSIQ_B_SENSE_LEN 20
1038#define ASC_SCSIQ_DONE_INFO_BEG 22
1039#define ASC_SCSIQ_D_SRBPTR 22
1040#define ASC_SCSIQ_B_TARGET_IX 26
1041#define ASC_SCSIQ_B_CDB_LEN 28
1042#define ASC_SCSIQ_B_TAG_CODE 29
1043#define ASC_SCSIQ_W_VM_ID 30
1044#define ASC_SCSIQ_DONE_STATUS 32
1045#define ASC_SCSIQ_HOST_STATUS 33
1046#define ASC_SCSIQ_SCSI_STATUS 34
1047#define ASC_SCSIQ_CDB_BEG 36
1048#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
1049#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
1050#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
1051#define ASC_SCSIQ_B_SG_WK_QP 49
1052#define ASC_SCSIQ_B_SG_WK_IX 50
1053#define ASC_SCSIQ_W_ALT_DC1 52
1054#define ASC_SCSIQ_B_LIST_CNT 6
1055#define ASC_SCSIQ_B_CUR_LIST_CNT 7
1056#define ASC_SGQ_B_SG_CNTL 4
1057#define ASC_SGQ_B_SG_HEAD_QP 5
1058#define ASC_SGQ_B_SG_LIST_CNT 6
1059#define ASC_SGQ_B_SG_CUR_LIST_CNT 7
1060#define ASC_SGQ_LIST_BEG 8
1061#define ASC_DEF_SCSI1_QNG 4
1062#define ASC_MAX_SCSI1_QNG 4
1063#define ASC_DEF_SCSI2_QNG 16
1064#define ASC_MAX_SCSI2_QNG 32
1065#define ASC_TAG_CODE_MASK 0x23
1066#define ASC_STOP_REQ_RISC_STOP 0x01
1067#define ASC_STOP_ACK_RISC_STOP 0x03
1068#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10
1069#define ASC_STOP_CLEAN_UP_DISC_Q 0x20
1070#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
1071#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
1072#define ASC_TID_TO_TARGET_ID(tid) (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
1073#define ASC_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ASC_MAX_TID))
1074#define ASC_TIX_TO_TID(tix) ((tix) & ASC_MAX_TID)
1075#define ASC_TID_TO_TIX(tid) ((tid) & ASC_MAX_TID)
1076#define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
1077#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
1078
1079typedef struct asc_scsiq_1 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001080 uchar status;
1081 uchar q_no;
1082 uchar cntl;
1083 uchar sg_queue_cnt;
1084 uchar target_id;
1085 uchar target_lun;
1086 ASC_PADDR data_addr;
1087 ASC_DCNT data_cnt;
1088 ASC_PADDR sense_addr;
1089 uchar sense_len;
1090 uchar extra_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091} ASC_SCSIQ_1;
1092
1093typedef struct asc_scsiq_2 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001094 ASC_VADDR srb_ptr;
1095 uchar target_ix;
1096 uchar flag;
1097 uchar cdb_len;
1098 uchar tag_code;
1099 ushort vm_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100} ASC_SCSIQ_2;
1101
1102typedef struct asc_scsiq_3 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001103 uchar done_stat;
1104 uchar host_stat;
1105 uchar scsi_stat;
1106 uchar scsi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107} ASC_SCSIQ_3;
1108
1109typedef struct asc_scsiq_4 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001110 uchar cdb[ASC_MAX_CDB_LEN];
1111 uchar y_first_sg_list_qp;
1112 uchar y_working_sg_qp;
1113 uchar y_working_sg_ix;
1114 uchar y_res;
1115 ushort x_req_count;
1116 ushort x_reconnect_rtn;
1117 ASC_PADDR x_saved_data_addr;
1118 ASC_DCNT x_saved_data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119} ASC_SCSIQ_4;
1120
1121typedef struct asc_q_done_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001122 ASC_SCSIQ_2 d2;
1123 ASC_SCSIQ_3 d3;
1124 uchar q_status;
1125 uchar q_no;
1126 uchar cntl;
1127 uchar sense_len;
1128 uchar extra_bytes;
1129 uchar res;
1130 ASC_DCNT remain_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131} ASC_QDONE_INFO;
1132
1133typedef struct asc_sg_list {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001134 ASC_PADDR addr;
1135 ASC_DCNT bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136} ASC_SG_LIST;
1137
1138typedef struct asc_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001139 ushort entry_cnt;
1140 ushort queue_cnt;
1141 ushort entry_to_copy;
1142 ushort res;
1143 ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144} ASC_SG_HEAD;
1145
1146#define ASC_MIN_SG_LIST 2
1147
1148typedef struct asc_min_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001149 ushort entry_cnt;
1150 ushort queue_cnt;
1151 ushort entry_to_copy;
1152 ushort res;
1153 ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154} ASC_MIN_SG_HEAD;
1155
1156#define QCX_SORT (0x0001)
1157#define QCX_COALEASE (0x0002)
1158
1159typedef struct asc_scsi_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001160 ASC_SCSIQ_1 q1;
1161 ASC_SCSIQ_2 q2;
1162 uchar *cdbptr;
1163 ASC_SG_HEAD *sg_head;
1164 ushort remain_sg_entry_cnt;
1165 ushort next_sg_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166} ASC_SCSI_Q;
1167
1168typedef struct asc_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001169 ASC_SCSIQ_1 r1;
1170 ASC_SCSIQ_2 r2;
1171 uchar *cdbptr;
1172 ASC_SG_HEAD *sg_head;
1173 uchar *sense_ptr;
1174 ASC_SCSIQ_3 r3;
1175 uchar cdb[ASC_MAX_CDB_LEN];
1176 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177} ASC_SCSI_REQ_Q;
1178
1179typedef struct asc_scsi_bios_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001180 ASC_SCSIQ_1 r1;
1181 ASC_SCSIQ_2 r2;
1182 uchar *cdbptr;
1183 ASC_SG_HEAD *sg_head;
1184 uchar *sense_ptr;
1185 ASC_SCSIQ_3 r3;
1186 uchar cdb[ASC_MAX_CDB_LEN];
1187 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188} ASC_SCSI_BIOS_REQ_Q;
1189
1190typedef struct asc_risc_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001191 uchar fwd;
1192 uchar bwd;
1193 ASC_SCSIQ_1 i1;
1194 ASC_SCSIQ_2 i2;
1195 ASC_SCSIQ_3 i3;
1196 ASC_SCSIQ_4 i4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197} ASC_RISC_Q;
1198
1199typedef struct asc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001200 uchar seq_no;
1201 uchar q_no;
1202 uchar cntl;
1203 uchar sg_head_qp;
1204 uchar sg_list_cnt;
1205 uchar sg_cur_list_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206} ASC_SG_LIST_Q;
1207
1208typedef struct asc_risc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001209 uchar fwd;
1210 uchar bwd;
1211 ASC_SG_LIST_Q sg;
1212 ASC_SG_LIST sg_list[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213} ASC_RISC_SG_LIST_Q;
1214
1215#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
1216#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024
1217#define ASCQ_ERR_NO_ERROR 0
1218#define ASCQ_ERR_IO_NOT_FOUND 1
1219#define ASCQ_ERR_LOCAL_MEM 2
1220#define ASCQ_ERR_CHKSUM 3
1221#define ASCQ_ERR_START_CHIP 4
1222#define ASCQ_ERR_INT_TARGET_ID 5
1223#define ASCQ_ERR_INT_LOCAL_MEM 6
1224#define ASCQ_ERR_HALT_RISC 7
1225#define ASCQ_ERR_GET_ASPI_ENTRY 8
1226#define ASCQ_ERR_CLOSE_ASPI 9
1227#define ASCQ_ERR_HOST_INQUIRY 0x0A
1228#define ASCQ_ERR_SAVED_SRB_BAD 0x0B
1229#define ASCQ_ERR_QCNTL_SG_LIST 0x0C
1230#define ASCQ_ERR_Q_STATUS 0x0D
1231#define ASCQ_ERR_WR_SCSIQ 0x0E
1232#define ASCQ_ERR_PC_ADDR 0x0F
1233#define ASCQ_ERR_SYN_OFFSET 0x10
1234#define ASCQ_ERR_SYN_XFER_TIME 0x11
1235#define ASCQ_ERR_LOCK_DMA 0x12
1236#define ASCQ_ERR_UNLOCK_DMA 0x13
1237#define ASCQ_ERR_VDS_CHK_INSTALL 0x14
1238#define ASCQ_ERR_MICRO_CODE_HALT 0x15
1239#define ASCQ_ERR_SET_LRAM_ADDR 0x16
1240#define ASCQ_ERR_CUR_QNG 0x17
1241#define ASCQ_ERR_SG_Q_LINKS 0x18
1242#define ASCQ_ERR_SCSIQ_PTR 0x19
1243#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
1244#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
1245#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
1246#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D
1247#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
1248#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F
1249#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20
1250#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21
1251#define ASCQ_ERR_SEND_SCSI_Q 0x22
1252#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23
1253#define ASCQ_ERR_RESET_SDTR 0x24
1254
1255/*
1256 * Warning code values are set in ASC_DVC_VAR 'warn_code'.
1257 */
1258#define ASC_WARN_NO_ERROR 0x0000
1259#define ASC_WARN_IO_PORT_ROTATE 0x0001
1260#define ASC_WARN_EEPROM_CHKSUM 0x0002
1261#define ASC_WARN_IRQ_MODIFIED 0x0004
1262#define ASC_WARN_AUTO_CONFIG 0x0008
1263#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
1264#define ASC_WARN_EEPROM_RECOVER 0x0020
1265#define ASC_WARN_CFG_MSW_RECOVER 0x0040
1266#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
1267
1268/*
1269 * Error code values are set in ASC_DVC_VAR 'err_code'.
1270 */
1271#define ASC_IERR_WRITE_EEPROM 0x0001
1272#define ASC_IERR_MCODE_CHKSUM 0x0002
1273#define ASC_IERR_SET_PC_ADDR 0x0004
1274#define ASC_IERR_START_STOP_CHIP 0x0008
1275#define ASC_IERR_IRQ_NO 0x0010
1276#define ASC_IERR_SET_IRQ_NO 0x0020
1277#define ASC_IERR_CHIP_VERSION 0x0040
1278#define ASC_IERR_SET_SCSI_ID 0x0080
1279#define ASC_IERR_GET_PHY_ADDR 0x0100
1280#define ASC_IERR_BAD_SIGNATURE 0x0200
1281#define ASC_IERR_NO_BUS_TYPE 0x0400
1282#define ASC_IERR_SCAM 0x0800
1283#define ASC_IERR_SET_SDTR 0x1000
1284#define ASC_IERR_RW_LRAM 0x8000
1285
1286#define ASC_DEF_IRQ_NO 10
1287#define ASC_MAX_IRQ_NO 15
1288#define ASC_MIN_IRQ_NO 10
1289#define ASC_MIN_REMAIN_Q (0x02)
1290#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
1291#define ASC_MIN_TAG_Q_PER_DVC (0x04)
1292#define ASC_DEF_TAG_Q_PER_DVC (0x04)
1293#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q
1294#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
1295#define ASC_MAX_TOTAL_QNG 240
1296#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
1297#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
1298#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
1299#define ASC_MAX_INRAM_TAG_QNG 16
1300#define ASC_IOADR_TABLE_MAX_IX 11
1301#define ASC_IOADR_GAP 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302#define ASC_LIB_SCSIQ_WK_SP 256
1303#define ASC_MAX_SYN_XFER_NO 16
1304#define ASC_SYN_MAX_OFFSET 0x0F
1305#define ASC_DEF_SDTR_OFFSET 0x0F
1306#define ASC_DEF_SDTR_INDEX 0x00
1307#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
1308#define SYN_XFER_NS_0 25
1309#define SYN_XFER_NS_1 30
1310#define SYN_XFER_NS_2 35
1311#define SYN_XFER_NS_3 40
1312#define SYN_XFER_NS_4 50
1313#define SYN_XFER_NS_5 60
1314#define SYN_XFER_NS_6 70
1315#define SYN_XFER_NS_7 85
1316#define SYN_ULTRA_XFER_NS_0 12
1317#define SYN_ULTRA_XFER_NS_1 19
1318#define SYN_ULTRA_XFER_NS_2 25
1319#define SYN_ULTRA_XFER_NS_3 32
1320#define SYN_ULTRA_XFER_NS_4 38
1321#define SYN_ULTRA_XFER_NS_5 44
1322#define SYN_ULTRA_XFER_NS_6 50
1323#define SYN_ULTRA_XFER_NS_7 57
1324#define SYN_ULTRA_XFER_NS_8 63
1325#define SYN_ULTRA_XFER_NS_9 69
1326#define SYN_ULTRA_XFER_NS_10 75
1327#define SYN_ULTRA_XFER_NS_11 82
1328#define SYN_ULTRA_XFER_NS_12 88
1329#define SYN_ULTRA_XFER_NS_13 94
1330#define SYN_ULTRA_XFER_NS_14 100
1331#define SYN_ULTRA_XFER_NS_15 107
1332
1333typedef struct ext_msg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001334 uchar msg_type;
1335 uchar msg_len;
1336 uchar msg_req;
1337 union {
1338 struct {
1339 uchar sdtr_xfer_period;
1340 uchar sdtr_req_ack_offset;
1341 } sdtr;
1342 struct {
1343 uchar wdtr_width;
1344 } wdtr;
1345 struct {
1346 uchar mdp_b3;
1347 uchar mdp_b2;
1348 uchar mdp_b1;
1349 uchar mdp_b0;
1350 } mdp;
1351 } u_ext_msg;
1352 uchar res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353} EXT_MSG;
1354
1355#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
1356#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
1357#define wdtr_width u_ext_msg.wdtr.wdtr_width
1358#define mdp_b3 u_ext_msg.mdp_b3
1359#define mdp_b2 u_ext_msg.mdp_b2
1360#define mdp_b1 u_ext_msg.mdp_b1
1361#define mdp_b0 u_ext_msg.mdp_b0
1362
1363typedef struct asc_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001364 ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
1365 ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
1366 ASC_SCSI_BIT_ID_TYPE disc_enable;
1367 ASC_SCSI_BIT_ID_TYPE sdtr_enable;
1368 uchar chip_scsi_id;
1369 uchar isa_dma_speed;
1370 uchar isa_dma_channel;
1371 uchar chip_version;
1372 ushort lib_serial_no;
1373 ushort lib_version;
1374 ushort mcode_date;
1375 ushort mcode_version;
1376 uchar max_tag_qng[ASC_MAX_TID + 1];
1377 uchar *overrun_buf;
1378 uchar sdtr_period_offset[ASC_MAX_TID + 1];
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001379 uchar adapter_info[6];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380} ASC_DVC_CFG;
1381
1382#define ASC_DEF_DVC_CNTL 0xFFFF
1383#define ASC_DEF_CHIP_SCSI_ID 7
1384#define ASC_DEF_ISA_DMA_SPEED 4
1385#define ASC_INIT_STATE_NULL 0x0000
1386#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
1387#define ASC_INIT_STATE_END_GET_CFG 0x0002
1388#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
1389#define ASC_INIT_STATE_END_SET_CFG 0x0008
1390#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
1391#define ASC_INIT_STATE_END_LOAD_MC 0x0020
1392#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
1393#define ASC_INIT_STATE_END_INQUIRY 0x0080
1394#define ASC_INIT_RESET_SCSI_DONE 0x0100
1395#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
1397#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
1398#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
1399#define ASC_MIN_TAGGED_CMD 7
1400#define ASC_MAX_SCSI_RESET_WAIT 30
1401
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001402struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001405 PortAddr iop_base;
1406 ushort err_code;
1407 ushort dvc_cntl;
1408 ushort bug_fix_cntl;
1409 ushort bus_type;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001410 ASC_SCSI_BIT_ID_TYPE init_sdtr;
1411 ASC_SCSI_BIT_ID_TYPE sdtr_done;
1412 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
1413 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
1414 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
1415 ASC_SCSI_BIT_ID_TYPE start_motor;
1416 uchar scsi_reset_wait;
1417 uchar chip_no;
1418 char is_in_int;
1419 uchar max_total_qng;
1420 uchar cur_total_qng;
1421 uchar in_critical_cnt;
1422 uchar irq_no;
1423 uchar last_q_shortage;
1424 ushort init_state;
1425 uchar cur_dvc_qng[ASC_MAX_TID + 1];
1426 uchar max_dvc_qng[ASC_MAX_TID + 1];
1427 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
1428 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
1429 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
1430 ASC_DVC_CFG *cfg;
1431 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
1432 char redo_scam;
1433 ushort res2;
1434 uchar dos_int13_table[ASC_MAX_TID + 1];
1435 ASC_DCNT max_dma_count;
1436 ASC_SCSI_BIT_ID_TYPE no_scam;
1437 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
1438 uchar max_sdtr_index;
1439 uchar host_init_sdtr_index;
1440 struct asc_board *drv_ptr;
1441 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442} ASC_DVC_VAR;
1443
1444typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001445 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446} ASC_DVC_INQ_INFO;
1447
1448typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001449 ASC_DCNT lba;
1450 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451} ASC_CAP_INFO;
1452
1453typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001454 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455} ASC_CAP_INFO_ARRAY;
1456
1457#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
1458#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
1459#define ASC_CNTL_INITIATOR (ushort)0x0001
1460#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
1461#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
1462#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
1463#define ASC_CNTL_NO_SCAM (ushort)0x0010
1464#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
1465#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
1466#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
1467#define ASC_CNTL_RESET_SCSI (ushort)0x0200
1468#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
1469#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
1470#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
1471#define ASC_CNTL_BURST_MODE (ushort)0x2000
1472#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
1473#define ASC_EEP_DVC_CFG_BEG_VL 2
1474#define ASC_EEP_MAX_DVC_ADDR_VL 15
1475#define ASC_EEP_DVC_CFG_BEG 32
1476#define ASC_EEP_MAX_DVC_ADDR 45
1477#define ASC_EEP_DEFINED_WORDS 10
1478#define ASC_EEP_MAX_ADDR 63
1479#define ASC_EEP_RES_WORDS 0
1480#define ASC_EEP_MAX_RETRY 20
1481#define ASC_MAX_INIT_BUSY_RETRY 8
1482#define ASC_EEP_ISA_PNP_WSIZE 16
1483
1484/*
1485 * These macros keep the chip SCSI id and ISA DMA speed
1486 * bitfields in board order. C bitfields aren't portable
1487 * between big and little-endian platforms so they are
1488 * not used.
1489 */
1490
1491#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
1492#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
1493#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
1494 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
1495#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
1496 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
1497
1498typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001499 ushort cfg_lsw;
1500 ushort cfg_msw;
1501 uchar init_sdtr;
1502 uchar disc_enable;
1503 uchar use_cmd_qng;
1504 uchar start_motor;
1505 uchar max_total_qng;
1506 uchar max_tag_qng;
1507 uchar bios_scan;
1508 uchar power_up_wait;
1509 uchar no_scam;
1510 uchar id_speed; /* low order 4 bits is chip scsi id */
1511 /* high order 4 bits is isa dma speed */
1512 uchar dos_int13_table[ASC_MAX_TID + 1];
1513 uchar adapter_info[6];
1514 ushort cntl;
1515 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516} ASCEEP_CONFIG;
1517
1518#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
1519#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
1520#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
1521
1522#define ASC_EEP_CMD_READ 0x80
1523#define ASC_EEP_CMD_WRITE 0x40
1524#define ASC_EEP_CMD_WRITE_ABLE 0x30
1525#define ASC_EEP_CMD_WRITE_DISABLE 0x00
1526#define ASC_OVERRUN_BSIZE 0x00000048UL
1527#define ASC_CTRL_BREAK_ONCE 0x0001
1528#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
1529#define ASCV_MSGOUT_BEG 0x0000
1530#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
1531#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
1532#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
1533#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
1534#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
1535#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
1536#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
1537#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
1538#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
1539#define ASCV_BREAK_ADDR (ushort)0x0028
1540#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
1541#define ASCV_BREAK_CONTROL (ushort)0x002C
1542#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
1543
1544#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
1545#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
1546#define ASCV_MCODE_SIZE_W (ushort)0x0034
1547#define ASCV_STOP_CODE_B (ushort)0x0036
1548#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
1549#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
1550#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
1551#define ASCV_HALTCODE_W (ushort)0x0040
1552#define ASCV_CHKSUM_W (ushort)0x0042
1553#define ASCV_MC_DATE_W (ushort)0x0044
1554#define ASCV_MC_VER_W (ushort)0x0046
1555#define ASCV_NEXTRDY_B (ushort)0x0048
1556#define ASCV_DONENEXT_B (ushort)0x0049
1557#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
1558#define ASCV_SCSIBUSY_B (ushort)0x004B
1559#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
1560#define ASCV_CURCDB_B (ushort)0x004D
1561#define ASCV_RCLUN_B (ushort)0x004E
1562#define ASCV_BUSY_QHEAD_B (ushort)0x004F
1563#define ASCV_DISC1_QHEAD_B (ushort)0x0050
1564#define ASCV_DISC_ENABLE_B (ushort)0x0052
1565#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
1566#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
1567#define ASCV_MCODE_CNTL_B (ushort)0x0056
1568#define ASCV_NULL_TARGET_B (ushort)0x0057
1569#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
1570#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
1571#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
1572#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
1573#define ASCV_HOST_FLAG_B (ushort)0x005D
1574#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
1575#define ASCV_VER_SERIAL_B (ushort)0x0065
1576#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
1577#define ASCV_WTM_FLAG_B (ushort)0x0068
1578#define ASCV_RISC_FLAG_B (ushort)0x006A
1579#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
1580#define ASC_HOST_FLAG_IN_ISR 0x01
1581#define ASC_HOST_FLAG_ACK_INT 0x02
1582#define ASC_RISC_FLAG_GEN_INT 0x01
1583#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
1584#define IOP_CTRL (0x0F)
1585#define IOP_STATUS (0x0E)
1586#define IOP_INT_ACK IOP_STATUS
1587#define IOP_REG_IFC (0x0D)
1588#define IOP_SYN_OFFSET (0x0B)
1589#define IOP_EXTRA_CONTROL (0x0D)
1590#define IOP_REG_PC (0x0C)
1591#define IOP_RAM_ADDR (0x0A)
1592#define IOP_RAM_DATA (0x08)
1593#define IOP_EEP_DATA (0x06)
1594#define IOP_EEP_CMD (0x07)
1595#define IOP_VERSION (0x03)
1596#define IOP_CONFIG_HIGH (0x04)
1597#define IOP_CONFIG_LOW (0x02)
1598#define IOP_SIG_BYTE (0x01)
1599#define IOP_SIG_WORD (0x00)
1600#define IOP_REG_DC1 (0x0E)
1601#define IOP_REG_DC0 (0x0C)
1602#define IOP_REG_SB (0x0B)
1603#define IOP_REG_DA1 (0x0A)
1604#define IOP_REG_DA0 (0x08)
1605#define IOP_REG_SC (0x09)
1606#define IOP_DMA_SPEED (0x07)
1607#define IOP_REG_FLAG (0x07)
1608#define IOP_FIFO_H (0x06)
1609#define IOP_FIFO_L (0x04)
1610#define IOP_REG_ID (0x05)
1611#define IOP_REG_QP (0x03)
1612#define IOP_REG_IH (0x02)
1613#define IOP_REG_IX (0x01)
1614#define IOP_REG_AX (0x00)
1615#define IFC_REG_LOCK (0x00)
1616#define IFC_REG_UNLOCK (0x09)
1617#define IFC_WR_EN_FILTER (0x10)
1618#define IFC_RD_NO_EEPROM (0x10)
1619#define IFC_SLEW_RATE (0x20)
1620#define IFC_ACT_NEG (0x40)
1621#define IFC_INP_FILTER (0x80)
1622#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
1623#define SC_SEL (uchar)(0x80)
1624#define SC_BSY (uchar)(0x40)
1625#define SC_ACK (uchar)(0x20)
1626#define SC_REQ (uchar)(0x10)
1627#define SC_ATN (uchar)(0x08)
1628#define SC_IO (uchar)(0x04)
1629#define SC_CD (uchar)(0x02)
1630#define SC_MSG (uchar)(0x01)
1631#define SEC_SCSI_CTL (uchar)(0x80)
1632#define SEC_ACTIVE_NEGATE (uchar)(0x40)
1633#define SEC_SLEW_RATE (uchar)(0x20)
1634#define SEC_ENABLE_FILTER (uchar)(0x10)
1635#define ASC_HALT_EXTMSG_IN (ushort)0x8000
1636#define ASC_HALT_CHK_CONDITION (ushort)0x8100
1637#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
1638#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
1639#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
1640#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
1641#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
1642#define ASC_MAX_QNO 0xF8
1643#define ASC_DATA_SEC_BEG (ushort)0x0080
1644#define ASC_DATA_SEC_END (ushort)0x0080
1645#define ASC_CODE_SEC_BEG (ushort)0x0080
1646#define ASC_CODE_SEC_END (ushort)0x0080
1647#define ASC_QADR_BEG (0x4000)
1648#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
1649#define ASC_QADR_END (ushort)0x7FFF
1650#define ASC_QLAST_ADR (ushort)0x7FC0
1651#define ASC_QBLK_SIZE 0x40
1652#define ASC_BIOS_DATA_QBEG 0xF8
1653#define ASC_MIN_ACTIVE_QNO 0x01
1654#define ASC_QLINK_END 0xFF
1655#define ASC_EEPROM_WORDS 0x10
1656#define ASC_MAX_MGS_LEN 0x10
1657#define ASC_BIOS_ADDR_DEF 0xDC00
1658#define ASC_BIOS_SIZE 0x3800
1659#define ASC_BIOS_RAM_OFF 0x3800
1660#define ASC_BIOS_RAM_SIZE 0x800
1661#define ASC_BIOS_MIN_ADDR 0xC000
1662#define ASC_BIOS_MAX_ADDR 0xEC00
1663#define ASC_BIOS_BANK_SIZE 0x0400
1664#define ASC_MCODE_START_ADDR 0x0080
1665#define ASC_CFG0_HOST_INT_ON 0x0020
1666#define ASC_CFG0_BIOS_ON 0x0040
1667#define ASC_CFG0_VERA_BURST_ON 0x0080
1668#define ASC_CFG0_SCSI_PARITY_ON 0x0800
1669#define ASC_CFG1_SCSI_TARGET_ON 0x0080
1670#define ASC_CFG1_LRAM_8BITS_ON 0x0800
1671#define ASC_CFG_MSW_CLR_MASK 0x3080
1672#define CSW_TEST1 (ASC_CS_TYPE)0x8000
1673#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
1674#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
1675#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
1676#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
1677#define CSW_TEST2 (ASC_CS_TYPE)0x0400
1678#define CSW_TEST3 (ASC_CS_TYPE)0x0200
1679#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
1680#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
1681#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
1682#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
1683#define CSW_HALTED (ASC_CS_TYPE)0x0010
1684#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
1685#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
1686#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
1687#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
1688#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
1689#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
1690#define CIW_TEST1 (ASC_CS_TYPE)0x0200
1691#define CIW_TEST2 (ASC_CS_TYPE)0x0400
1692#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
1693#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
1694#define CC_CHIP_RESET (uchar)0x80
1695#define CC_SCSI_RESET (uchar)0x40
1696#define CC_HALT (uchar)0x20
1697#define CC_SINGLE_STEP (uchar)0x10
1698#define CC_DMA_ABLE (uchar)0x08
1699#define CC_TEST (uchar)0x04
1700#define CC_BANK_ONE (uchar)0x02
1701#define CC_DIAG (uchar)0x01
1702#define ASC_1000_ID0W 0x04C1
1703#define ASC_1000_ID0W_FIX 0x00C1
1704#define ASC_1000_ID1B 0x25
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705#define ASC_EISA_REV_IOP_MASK (0x0C83)
1706#define ASC_EISA_PID_IOP_MASK (0x0C80)
1707#define ASC_EISA_CFG_IOP_MASK (0x0C86)
1708#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709#define INS_HALTINT (ushort)0x6281
1710#define INS_HALT (ushort)0x6280
1711#define INS_SINT (ushort)0x6200
1712#define INS_RFLAG_WTM (ushort)0x7380
1713#define ASC_MC_SAVE_CODE_WSIZE 0x500
1714#define ASC_MC_SAVE_DATA_WSIZE 0x40
1715
1716typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001717 ushort data[ASC_MC_SAVE_DATA_WSIZE];
1718 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719} ASC_MC_SAVED;
1720
1721#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
1722#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
1723#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
1724#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
1725#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
1726#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
1727#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
1728#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
1729#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
1730#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
1731#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
1732#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
1733#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
1734#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
1735#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
1736#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
1737#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
1738#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
1739#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
1740#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
1741#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
1742#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
1743#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
1744#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
1745#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
1746#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
1747#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
1748#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
1749#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
1750#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
1751#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
1752#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
1753#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
1754#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
1755#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
1756#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
1757#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
1758#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
1759#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
1760#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
1761#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
1762#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
1763#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
1764#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
1765#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
1766#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
1767#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
1768#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
1769#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
1770#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
1771#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
1772#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
1773#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
1774#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
1775#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
1776#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
1777#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
1778#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
1779#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
1780#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
1781#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
1782#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
1783#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
1784#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
1785#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
1786#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
1787#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
1788#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
1789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001790static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
1791static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
1792static void AscWaitEEPRead(void);
1793static void AscWaitEEPWrite(void);
1794static ushort AscReadEEPWord(PortAddr, uchar);
1795static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
1796static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1797static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
1798static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1799static int AscStartChip(PortAddr);
1800static int AscStopChip(PortAddr);
1801static void AscSetChipIH(PortAddr, ushort);
1802static int AscIsChipHalted(PortAddr);
1803static void AscAckInterrupt(PortAddr);
1804static void AscDisableInterrupt(PortAddr);
1805static void AscEnableInterrupt(PortAddr);
1806static void AscSetBank(PortAddr, uchar);
1807static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001809static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001811static uchar AscReadLramByte(PortAddr, ushort);
1812static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001814static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001816static void AscWriteLramWord(PortAddr, ushort, ushort);
1817static void AscWriteLramByte(PortAddr, ushort, uchar);
1818static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
1819static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
1820static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1821static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1822static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
1823static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
1824static ushort AscInitFromEEP(ASC_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001825static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1826static int AscTestExternalLram(ASC_DVC_VAR *);
1827static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1828static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1829static void AscSetChipSDTR(PortAddr, uchar, uchar);
1830static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1831static uchar AscAllocFreeQueue(PortAddr, uchar);
1832static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1833static int AscHostReqRiscHalt(PortAddr);
1834static int AscStopQueueExe(PortAddr);
1835static int AscSendScsiQueue(ASC_DVC_VAR *,
1836 ASC_SCSI_Q *scsiq, uchar n_q_required);
1837static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1838static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1839static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1840static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1841static ushort AscInitLram(ASC_DVC_VAR *);
1842static ushort AscInitQLinkVar(ASC_DVC_VAR *);
1843static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1844static int AscIsrChipHalted(ASC_DVC_VAR *);
1845static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1846 ASC_QDONE_INFO *, ASC_DCNT);
1847static int AscIsrQDone(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001849static ushort AscGetEisaChipCfg(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001851static uchar AscGetChipScsiCtrl(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001852static uchar AscGetChipVersion(PortAddr, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001853static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001854static void AscToggleIRQAct(PortAddr);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001855static inline ulong DvcEnterCritical(void);
1856static inline void DvcLeaveCritical(ulong);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001857static void DvcSleepMilliSecond(ASC_DCNT);
1858static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
1859static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1860static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001861static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04001862static void AscAsyncFix(ASC_DVC_VAR *, struct scsi_device *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001863static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1864static int AscISR(ASC_DVC_VAR *);
1865static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1866static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001868static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001870static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
1872/*
1873 * --- Adv Library Constants and Macros
1874 */
1875
1876#define ADV_LIB_VERSION_MAJOR 5
1877#define ADV_LIB_VERSION_MINOR 14
1878
1879/*
1880 * Define Adv Library required special types.
1881 */
1882
1883/*
1884 * Portable Data Types
1885 *
1886 * Any instance where a 32-bit long or pointer type is assumed
1887 * for precision or HW defined structures, the following define
1888 * types must be used. In Linux the char, short, and int types
1889 * are all consistent at 8, 16, and 32 bits respectively. Pointers
1890 * and long types are 64 bits on Alpha and UltraSPARC.
1891 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001892#define ADV_PADDR __u32 /* Physical address data type. */
1893#define ADV_VADDR __u32 /* Virtual address data type. */
1894#define ADV_DCNT __u32 /* Unsigned Data count type. */
1895#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
1897/*
1898 * These macros are used to convert a virtual address to a
1899 * 32-bit value. This currently can be used on Linux Alpha
1900 * which uses 64-bit virtual address but a 32-bit bus address.
1901 * This is likely to break in the future, but doing this now
1902 * will give us time to change the HW and FW to handle 64-bit
1903 * addresses.
1904 */
1905#define ADV_VADDR_TO_U32 virt_to_bus
1906#define ADV_U32_TO_VADDR bus_to_virt
1907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001908#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
1910/*
1911 * Define Adv Library required memory access macros.
1912 */
1913#define ADV_MEM_READB(addr) readb(addr)
1914#define ADV_MEM_READW(addr) readw(addr)
1915#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
1916#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
1917#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
1918
1919#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
1920
1921/*
1922 * For wide boards a CDB length maximum of 16 bytes
1923 * is supported.
1924 */
1925#define ADV_MAX_CDB_LEN 16
1926
1927/*
1928 * Define total number of simultaneous maximum element scatter-gather
1929 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
1930 * maximum number of outstanding commands per wide host adapter. Each
1931 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
1932 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
1933 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
1934 * structures or 255 scatter-gather elements.
1935 *
1936 */
1937#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
1938
1939/*
1940 * Define Adv Library required maximum number of scatter-gather
1941 * elements per request.
1942 */
1943#define ADV_MAX_SG_LIST 255
1944
1945/* Number of SG blocks needed. */
1946#define ADV_NUM_SG_BLOCK \
1947 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
1948
1949/* Total contiguous memory needed for SG blocks. */
1950#define ADV_SG_TOTAL_MEM_SIZE \
1951 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
1952
1953#define ADV_PAGE_SIZE PAGE_SIZE
1954
1955#define ADV_NUM_PAGE_CROSSING \
1956 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
1957
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958#define ADV_EEP_DVC_CFG_BEGIN (0x00)
1959#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001960#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961#define ADV_EEP_MAX_WORD_ADDR (0x1E)
1962
1963#define ADV_EEP_DELAY_MS 100
1964
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001965#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
1966#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967/*
1968 * For the ASC3550 Bit 13 is Termination Polarity control bit.
1969 * For later ICs Bit 13 controls whether the CIS (Card Information
1970 * Service Section) is loaded from EEPROM.
1971 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001972#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
1973#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974/*
1975 * ASC38C1600 Bit 11
1976 *
1977 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
1978 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
1979 * Function 0 will specify INT B.
1980 *
1981 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
1982 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
1983 * Function 1 will specify INT A.
1984 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001985#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001987typedef struct adveep_3550_config {
1988 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001990 ushort cfg_lsw; /* 00 power up initialization */
1991 /* bit 13 set - Term Polarity Control */
1992 /* bit 14 set - BIOS Enable */
1993 /* bit 15 set - Big Endian Mode */
1994 ushort cfg_msw; /* 01 unused */
1995 ushort disc_enable; /* 02 disconnect enable */
1996 ushort wdtr_able; /* 03 Wide DTR able */
1997 ushort sdtr_able; /* 04 Synchronous DTR able */
1998 ushort start_motor; /* 05 send start up motor */
1999 ushort tagqng_able; /* 06 tag queuing able */
2000 ushort bios_scan; /* 07 BIOS device control */
2001 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002003 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2004 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002006 uchar scsi_reset_delay; /* 10 reset delay */
2007 uchar bios_id_lun; /* first boot device scsi id & lun */
2008 /* high nibble is lun */
2009 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002011 uchar termination; /* 11 0 - automatic */
2012 /* 1 - low off / high off */
2013 /* 2 - low off / high on */
2014 /* 3 - low on / high on */
2015 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002017 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002019 ushort bios_ctrl; /* 12 BIOS control bits */
2020 /* bit 0 BIOS don't act as initiator. */
2021 /* bit 1 BIOS > 1 GB support */
2022 /* bit 2 BIOS > 2 Disk Support */
2023 /* bit 3 BIOS don't support removables */
2024 /* bit 4 BIOS support bootable CD */
2025 /* bit 5 BIOS scan enabled */
2026 /* bit 6 BIOS support multiple LUNs */
2027 /* bit 7 BIOS display of message */
2028 /* bit 8 SCAM disabled */
2029 /* bit 9 Reset SCSI bus during init. */
2030 /* bit 10 */
2031 /* bit 11 No verbose initialization. */
2032 /* bit 12 SCSI parity enabled */
2033 /* bit 13 */
2034 /* bit 14 */
2035 /* bit 15 */
2036 ushort ultra_able; /* 13 ULTRA speed able */
2037 ushort reserved2; /* 14 reserved */
2038 uchar max_host_qng; /* 15 maximum host queuing */
2039 uchar max_dvc_qng; /* maximum per device queuing */
2040 ushort dvc_cntl; /* 16 control bit for driver */
2041 ushort bug_fix; /* 17 control bit for bug fix */
2042 ushort serial_number_word1; /* 18 Board serial number word 1 */
2043 ushort serial_number_word2; /* 19 Board serial number word 2 */
2044 ushort serial_number_word3; /* 20 Board serial number word 3 */
2045 ushort check_sum; /* 21 EEP check sum */
2046 uchar oem_name[16]; /* 22 OEM name */
2047 ushort dvc_err_code; /* 30 last device driver error code */
2048 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2049 ushort adv_err_addr; /* 32 last uc error address */
2050 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2051 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2052 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2053 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054} ADVEEP_3550_CONFIG;
2055
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002056typedef struct adveep_38C0800_config {
2057 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002059 ushort cfg_lsw; /* 00 power up initialization */
2060 /* bit 13 set - Load CIS */
2061 /* bit 14 set - BIOS Enable */
2062 /* bit 15 set - Big Endian Mode */
2063 ushort cfg_msw; /* 01 unused */
2064 ushort disc_enable; /* 02 disconnect enable */
2065 ushort wdtr_able; /* 03 Wide DTR able */
2066 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2067 ushort start_motor; /* 05 send start up motor */
2068 ushort tagqng_able; /* 06 tag queuing able */
2069 ushort bios_scan; /* 07 BIOS device control */
2070 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002072 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2073 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002075 uchar scsi_reset_delay; /* 10 reset delay */
2076 uchar bios_id_lun; /* first boot device scsi id & lun */
2077 /* high nibble is lun */
2078 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002080 uchar termination_se; /* 11 0 - automatic */
2081 /* 1 - low off / high off */
2082 /* 2 - low off / high on */
2083 /* 3 - low on / high on */
2084 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002086 uchar termination_lvd; /* 11 0 - automatic */
2087 /* 1 - low off / high off */
2088 /* 2 - low off / high on */
2089 /* 3 - low on / high on */
2090 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002092 ushort bios_ctrl; /* 12 BIOS control bits */
2093 /* bit 0 BIOS don't act as initiator. */
2094 /* bit 1 BIOS > 1 GB support */
2095 /* bit 2 BIOS > 2 Disk Support */
2096 /* bit 3 BIOS don't support removables */
2097 /* bit 4 BIOS support bootable CD */
2098 /* bit 5 BIOS scan enabled */
2099 /* bit 6 BIOS support multiple LUNs */
2100 /* bit 7 BIOS display of message */
2101 /* bit 8 SCAM disabled */
2102 /* bit 9 Reset SCSI bus during init. */
2103 /* bit 10 */
2104 /* bit 11 No verbose initialization. */
2105 /* bit 12 SCSI parity enabled */
2106 /* bit 13 */
2107 /* bit 14 */
2108 /* bit 15 */
2109 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2110 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2111 uchar max_host_qng; /* 15 maximum host queueing */
2112 uchar max_dvc_qng; /* maximum per device queuing */
2113 ushort dvc_cntl; /* 16 control bit for driver */
2114 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2115 ushort serial_number_word1; /* 18 Board serial number word 1 */
2116 ushort serial_number_word2; /* 19 Board serial number word 2 */
2117 ushort serial_number_word3; /* 20 Board serial number word 3 */
2118 ushort check_sum; /* 21 EEP check sum */
2119 uchar oem_name[16]; /* 22 OEM name */
2120 ushort dvc_err_code; /* 30 last device driver error code */
2121 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2122 ushort adv_err_addr; /* 32 last uc error address */
2123 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2124 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2125 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2126 ushort reserved36; /* 36 reserved */
2127 ushort reserved37; /* 37 reserved */
2128 ushort reserved38; /* 38 reserved */
2129 ushort reserved39; /* 39 reserved */
2130 ushort reserved40; /* 40 reserved */
2131 ushort reserved41; /* 41 reserved */
2132 ushort reserved42; /* 42 reserved */
2133 ushort reserved43; /* 43 reserved */
2134 ushort reserved44; /* 44 reserved */
2135 ushort reserved45; /* 45 reserved */
2136 ushort reserved46; /* 46 reserved */
2137 ushort reserved47; /* 47 reserved */
2138 ushort reserved48; /* 48 reserved */
2139 ushort reserved49; /* 49 reserved */
2140 ushort reserved50; /* 50 reserved */
2141 ushort reserved51; /* 51 reserved */
2142 ushort reserved52; /* 52 reserved */
2143 ushort reserved53; /* 53 reserved */
2144 ushort reserved54; /* 54 reserved */
2145 ushort reserved55; /* 55 reserved */
2146 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2147 ushort cisprt_msw; /* 57 CIS PTR MSW */
2148 ushort subsysvid; /* 58 SubSystem Vendor ID */
2149 ushort subsysid; /* 59 SubSystem ID */
2150 ushort reserved60; /* 60 reserved */
2151 ushort reserved61; /* 61 reserved */
2152 ushort reserved62; /* 62 reserved */
2153 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154} ADVEEP_38C0800_CONFIG;
2155
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002156typedef struct adveep_38C1600_config {
2157 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002159 ushort cfg_lsw; /* 00 power up initialization */
2160 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
2161 /* clear - Func. 0 INTA, Func. 1 INTB */
2162 /* bit 13 set - Load CIS */
2163 /* bit 14 set - BIOS Enable */
2164 /* bit 15 set - Big Endian Mode */
2165 ushort cfg_msw; /* 01 unused */
2166 ushort disc_enable; /* 02 disconnect enable */
2167 ushort wdtr_able; /* 03 Wide DTR able */
2168 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2169 ushort start_motor; /* 05 send start up motor */
2170 ushort tagqng_able; /* 06 tag queuing able */
2171 ushort bios_scan; /* 07 BIOS device control */
2172 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002174 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2175 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002177 uchar scsi_reset_delay; /* 10 reset delay */
2178 uchar bios_id_lun; /* first boot device scsi id & lun */
2179 /* high nibble is lun */
2180 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002182 uchar termination_se; /* 11 0 - automatic */
2183 /* 1 - low off / high off */
2184 /* 2 - low off / high on */
2185 /* 3 - low on / high on */
2186 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002188 uchar termination_lvd; /* 11 0 - automatic */
2189 /* 1 - low off / high off */
2190 /* 2 - low off / high on */
2191 /* 3 - low on / high on */
2192 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002194 ushort bios_ctrl; /* 12 BIOS control bits */
2195 /* bit 0 BIOS don't act as initiator. */
2196 /* bit 1 BIOS > 1 GB support */
2197 /* bit 2 BIOS > 2 Disk Support */
2198 /* bit 3 BIOS don't support removables */
2199 /* bit 4 BIOS support bootable CD */
2200 /* bit 5 BIOS scan enabled */
2201 /* bit 6 BIOS support multiple LUNs */
2202 /* bit 7 BIOS display of message */
2203 /* bit 8 SCAM disabled */
2204 /* bit 9 Reset SCSI bus during init. */
2205 /* bit 10 Basic Integrity Checking disabled */
2206 /* bit 11 No verbose initialization. */
2207 /* bit 12 SCSI parity enabled */
2208 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
2209 /* bit 14 */
2210 /* bit 15 */
2211 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2212 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2213 uchar max_host_qng; /* 15 maximum host queueing */
2214 uchar max_dvc_qng; /* maximum per device queuing */
2215 ushort dvc_cntl; /* 16 control bit for driver */
2216 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2217 ushort serial_number_word1; /* 18 Board serial number word 1 */
2218 ushort serial_number_word2; /* 19 Board serial number word 2 */
2219 ushort serial_number_word3; /* 20 Board serial number word 3 */
2220 ushort check_sum; /* 21 EEP check sum */
2221 uchar oem_name[16]; /* 22 OEM name */
2222 ushort dvc_err_code; /* 30 last device driver error code */
2223 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2224 ushort adv_err_addr; /* 32 last uc error address */
2225 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2226 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2227 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2228 ushort reserved36; /* 36 reserved */
2229 ushort reserved37; /* 37 reserved */
2230 ushort reserved38; /* 38 reserved */
2231 ushort reserved39; /* 39 reserved */
2232 ushort reserved40; /* 40 reserved */
2233 ushort reserved41; /* 41 reserved */
2234 ushort reserved42; /* 42 reserved */
2235 ushort reserved43; /* 43 reserved */
2236 ushort reserved44; /* 44 reserved */
2237 ushort reserved45; /* 45 reserved */
2238 ushort reserved46; /* 46 reserved */
2239 ushort reserved47; /* 47 reserved */
2240 ushort reserved48; /* 48 reserved */
2241 ushort reserved49; /* 49 reserved */
2242 ushort reserved50; /* 50 reserved */
2243 ushort reserved51; /* 51 reserved */
2244 ushort reserved52; /* 52 reserved */
2245 ushort reserved53; /* 53 reserved */
2246 ushort reserved54; /* 54 reserved */
2247 ushort reserved55; /* 55 reserved */
2248 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2249 ushort cisprt_msw; /* 57 CIS PTR MSW */
2250 ushort subsysvid; /* 58 SubSystem Vendor ID */
2251 ushort subsysid; /* 59 SubSystem ID */
2252 ushort reserved60; /* 60 reserved */
2253 ushort reserved61; /* 61 reserved */
2254 ushort reserved62; /* 62 reserved */
2255 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256} ADVEEP_38C1600_CONFIG;
2257
2258/*
2259 * EEPROM Commands
2260 */
2261#define ASC_EEP_CMD_DONE 0x0200
2262#define ASC_EEP_CMD_DONE_ERR 0x0001
2263
2264/* cfg_word */
2265#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
2266
2267/* bios_ctrl */
2268#define BIOS_CTRL_BIOS 0x0001
2269#define BIOS_CTRL_EXTENDED_XLAT 0x0002
2270#define BIOS_CTRL_GT_2_DISK 0x0004
2271#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
2272#define BIOS_CTRL_BOOTABLE_CD 0x0010
2273#define BIOS_CTRL_MULTIPLE_LUN 0x0040
2274#define BIOS_CTRL_DISPLAY_MSG 0x0080
2275#define BIOS_CTRL_NO_SCAM 0x0100
2276#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
2277#define BIOS_CTRL_INIT_VERBOSE 0x0800
2278#define BIOS_CTRL_SCSI_PARITY 0x1000
2279#define BIOS_CTRL_AIPP_DIS 0x2000
2280
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002281#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002283#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284
2285/*
2286 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
2287 * a special 16K Adv Library and Microcode version. After the issue is
2288 * resolved, should restore 32K support.
2289 *
2290 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
2291 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002292#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293
2294/*
2295 * Byte I/O register address from base of 'iop_base'.
2296 */
2297#define IOPB_INTR_STATUS_REG 0x00
2298#define IOPB_CHIP_ID_1 0x01
2299#define IOPB_INTR_ENABLES 0x02
2300#define IOPB_CHIP_TYPE_REV 0x03
2301#define IOPB_RES_ADDR_4 0x04
2302#define IOPB_RES_ADDR_5 0x05
2303#define IOPB_RAM_DATA 0x06
2304#define IOPB_RES_ADDR_7 0x07
2305#define IOPB_FLAG_REG 0x08
2306#define IOPB_RES_ADDR_9 0x09
2307#define IOPB_RISC_CSR 0x0A
2308#define IOPB_RES_ADDR_B 0x0B
2309#define IOPB_RES_ADDR_C 0x0C
2310#define IOPB_RES_ADDR_D 0x0D
2311#define IOPB_SOFT_OVER_WR 0x0E
2312#define IOPB_RES_ADDR_F 0x0F
2313#define IOPB_MEM_CFG 0x10
2314#define IOPB_RES_ADDR_11 0x11
2315#define IOPB_GPIO_DATA 0x12
2316#define IOPB_RES_ADDR_13 0x13
2317#define IOPB_FLASH_PAGE 0x14
2318#define IOPB_RES_ADDR_15 0x15
2319#define IOPB_GPIO_CNTL 0x16
2320#define IOPB_RES_ADDR_17 0x17
2321#define IOPB_FLASH_DATA 0x18
2322#define IOPB_RES_ADDR_19 0x19
2323#define IOPB_RES_ADDR_1A 0x1A
2324#define IOPB_RES_ADDR_1B 0x1B
2325#define IOPB_RES_ADDR_1C 0x1C
2326#define IOPB_RES_ADDR_1D 0x1D
2327#define IOPB_RES_ADDR_1E 0x1E
2328#define IOPB_RES_ADDR_1F 0x1F
2329#define IOPB_DMA_CFG0 0x20
2330#define IOPB_DMA_CFG1 0x21
2331#define IOPB_TICKLE 0x22
2332#define IOPB_DMA_REG_WR 0x23
2333#define IOPB_SDMA_STATUS 0x24
2334#define IOPB_SCSI_BYTE_CNT 0x25
2335#define IOPB_HOST_BYTE_CNT 0x26
2336#define IOPB_BYTE_LEFT_TO_XFER 0x27
2337#define IOPB_BYTE_TO_XFER_0 0x28
2338#define IOPB_BYTE_TO_XFER_1 0x29
2339#define IOPB_BYTE_TO_XFER_2 0x2A
2340#define IOPB_BYTE_TO_XFER_3 0x2B
2341#define IOPB_ACC_GRP 0x2C
2342#define IOPB_RES_ADDR_2D 0x2D
2343#define IOPB_DEV_ID 0x2E
2344#define IOPB_RES_ADDR_2F 0x2F
2345#define IOPB_SCSI_DATA 0x30
2346#define IOPB_RES_ADDR_31 0x31
2347#define IOPB_RES_ADDR_32 0x32
2348#define IOPB_SCSI_DATA_HSHK 0x33
2349#define IOPB_SCSI_CTRL 0x34
2350#define IOPB_RES_ADDR_35 0x35
2351#define IOPB_RES_ADDR_36 0x36
2352#define IOPB_RES_ADDR_37 0x37
2353#define IOPB_RAM_BIST 0x38
2354#define IOPB_PLL_TEST 0x39
2355#define IOPB_PCI_INT_CFG 0x3A
2356#define IOPB_RES_ADDR_3B 0x3B
2357#define IOPB_RFIFO_CNT 0x3C
2358#define IOPB_RES_ADDR_3D 0x3D
2359#define IOPB_RES_ADDR_3E 0x3E
2360#define IOPB_RES_ADDR_3F 0x3F
2361
2362/*
2363 * Word I/O register address from base of 'iop_base'.
2364 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002365#define IOPW_CHIP_ID_0 0x00 /* CID0 */
2366#define IOPW_CTRL_REG 0x02 /* CC */
2367#define IOPW_RAM_ADDR 0x04 /* LA */
2368#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002370#define IOPW_RISC_CSR 0x0A /* CSR */
2371#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
2372#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002374#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002376#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002378#define IOPW_EE_CMD 0x1A /* EC */
2379#define IOPW_EE_DATA 0x1C /* ED */
2380#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002382#define IOPW_Q_BASE 0x22 /* QB */
2383#define IOPW_QP 0x24 /* QP */
2384#define IOPW_IX 0x26 /* IX */
2385#define IOPW_SP 0x28 /* SP */
2386#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387#define IOPW_RES_ADDR_2C 0x2C
2388#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002389#define IOPW_SCSI_DATA 0x30 /* SD */
2390#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
2391#define IOPW_SCSI_CTRL 0x34 /* SC */
2392#define IOPW_HSHK_CFG 0x36 /* HCFG */
2393#define IOPW_SXFR_STATUS 0x36 /* SXS */
2394#define IOPW_SXFR_CNTL 0x38 /* SXL */
2395#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002397#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398
2399/*
2400 * Doubleword I/O register address from base of 'iop_base'.
2401 */
2402#define IOPDW_RES_ADDR_0 0x00
2403#define IOPDW_RAM_DATA 0x04
2404#define IOPDW_RES_ADDR_8 0x08
2405#define IOPDW_RES_ADDR_C 0x0C
2406#define IOPDW_RES_ADDR_10 0x10
2407#define IOPDW_COMMA 0x14
2408#define IOPDW_COMMB 0x18
2409#define IOPDW_RES_ADDR_1C 0x1C
2410#define IOPDW_SDMA_ADDR0 0x20
2411#define IOPDW_SDMA_ADDR1 0x24
2412#define IOPDW_SDMA_COUNT 0x28
2413#define IOPDW_SDMA_ERROR 0x2C
2414#define IOPDW_RDMA_ADDR0 0x30
2415#define IOPDW_RDMA_ADDR1 0x34
2416#define IOPDW_RDMA_COUNT 0x38
2417#define IOPDW_RDMA_ERROR 0x3C
2418
2419#define ADV_CHIP_ID_BYTE 0x25
2420#define ADV_CHIP_ID_WORD 0x04C1
2421
2422#define ADV_SC_SCSI_BUS_RESET 0x2000
2423
2424#define ADV_INTR_ENABLE_HOST_INTR 0x01
2425#define ADV_INTR_ENABLE_SEL_INTR 0x02
2426#define ADV_INTR_ENABLE_DPR_INTR 0x04
2427#define ADV_INTR_ENABLE_RTA_INTR 0x08
2428#define ADV_INTR_ENABLE_RMA_INTR 0x10
2429#define ADV_INTR_ENABLE_RST_INTR 0x20
2430#define ADV_INTR_ENABLE_DPE_INTR 0x40
2431#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
2432
2433#define ADV_INTR_STATUS_INTRA 0x01
2434#define ADV_INTR_STATUS_INTRB 0x02
2435#define ADV_INTR_STATUS_INTRC 0x04
2436
2437#define ADV_RISC_CSR_STOP (0x0000)
2438#define ADV_RISC_TEST_COND (0x2000)
2439#define ADV_RISC_CSR_RUN (0x4000)
2440#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
2441
2442#define ADV_CTRL_REG_HOST_INTR 0x0100
2443#define ADV_CTRL_REG_SEL_INTR 0x0200
2444#define ADV_CTRL_REG_DPR_INTR 0x0400
2445#define ADV_CTRL_REG_RTA_INTR 0x0800
2446#define ADV_CTRL_REG_RMA_INTR 0x1000
2447#define ADV_CTRL_REG_RES_BIT14 0x2000
2448#define ADV_CTRL_REG_DPE_INTR 0x4000
2449#define ADV_CTRL_REG_POWER_DONE 0x8000
2450#define ADV_CTRL_REG_ANY_INTR 0xFF00
2451
2452#define ADV_CTRL_REG_CMD_RESET 0x00C6
2453#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
2454#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
2455#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
2456#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
2457
2458#define ADV_TICKLE_NOP 0x00
2459#define ADV_TICKLE_A 0x01
2460#define ADV_TICKLE_B 0x02
2461#define ADV_TICKLE_C 0x03
2462
2463#define ADV_SCSI_CTRL_RSTOUT 0x2000
2464
2465#define AdvIsIntPending(port) \
2466 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
2467
2468/*
2469 * SCSI_CFG0 Register bit definitions
2470 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002471#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
2472#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
2473#define EVEN_PARITY 0x1000 /* Select Even Parity */
2474#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
2475#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
2476#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
2477#define SCAM_EN 0x0080 /* Enable SCAM selection */
2478#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
2479#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
2480#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
2481#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482
2483/*
2484 * SCSI_CFG1 Register bit definitions
2485 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002486#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
2487#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
2488#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
2489#define FILTER_SEL 0x0C00 /* Filter Period Selection */
2490#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
2491#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
2492#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
2493#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
2494#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
2495#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
2496#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
2497#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
2498#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
2499#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
2500#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501
2502/*
2503 * Addendum for ASC-38C0800 Chip
2504 *
2505 * The ASC-38C1600 Chip uses the same definitions except that the
2506 * bus mode override bits [12:10] have been moved to byte register
2507 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
2508 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
2509 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
2510 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
2511 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
2512 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002513#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
2514#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
2515#define HVD 0x1000 /* HVD Device Detect */
2516#define LVD 0x0800 /* LVD Device Detect */
2517#define SE 0x0400 /* SE Device Detect */
2518#define TERM_LVD 0x00C0 /* LVD Termination Bits */
2519#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
2520#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
2521#define TERM_SE 0x0030 /* SE Termination Bits */
2522#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
2523#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
2524#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
2525#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
2526#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
2527#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
2528#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
2529#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530
2531#define CABLE_ILLEGAL_A 0x7
2532 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
2533
2534#define CABLE_ILLEGAL_B 0xB
2535 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
2536
2537/*
2538 * MEM_CFG Register bit definitions
2539 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002540#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
2541#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
2542#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
2543#define RAM_SZ_2KB 0x00 /* 2 KB */
2544#define RAM_SZ_4KB 0x04 /* 4 KB */
2545#define RAM_SZ_8KB 0x08 /* 8 KB */
2546#define RAM_SZ_16KB 0x0C /* 16 KB */
2547#define RAM_SZ_32KB 0x10 /* 32 KB */
2548#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549
2550/*
2551 * DMA_CFG0 Register bit definitions
2552 *
2553 * This register is only accessible to the host.
2554 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002555#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
2556#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
2557#define FIFO_THRESH_16B 0x00 /* 16 bytes */
2558#define FIFO_THRESH_32B 0x20 /* 32 bytes */
2559#define FIFO_THRESH_48B 0x30 /* 48 bytes */
2560#define FIFO_THRESH_64B 0x40 /* 64 bytes */
2561#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
2562#define FIFO_THRESH_96B 0x60 /* 96 bytes */
2563#define FIFO_THRESH_112B 0x70 /* 112 bytes */
2564#define START_CTL 0x0C /* DMA start conditions */
2565#define START_CTL_TH 0x00 /* Wait threshold level (default) */
2566#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
2567#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
2568#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
2569#define READ_CMD 0x03 /* Memory Read Method */
2570#define READ_CMD_MR 0x00 /* Memory Read */
2571#define READ_CMD_MRL 0x02 /* Memory Read Long */
2572#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573
2574/*
2575 * ASC-38C0800 RAM BIST Register bit definitions
2576 */
2577#define RAM_TEST_MODE 0x80
2578#define PRE_TEST_MODE 0x40
2579#define NORMAL_MODE 0x00
2580#define RAM_TEST_DONE 0x10
2581#define RAM_TEST_STATUS 0x0F
2582#define RAM_TEST_HOST_ERROR 0x08
2583#define RAM_TEST_INTRAM_ERROR 0x04
2584#define RAM_TEST_RISC_ERROR 0x02
2585#define RAM_TEST_SCSI_ERROR 0x01
2586#define RAM_TEST_SUCCESS 0x00
2587#define PRE_TEST_VALUE 0x05
2588#define NORMAL_VALUE 0x00
2589
2590/*
2591 * ASC38C1600 Definitions
2592 *
2593 * IOPB_PCI_INT_CFG Bit Field Definitions
2594 */
2595
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002596#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597
2598/*
2599 * Bit 1 can be set to change the interrupt for the Function to operate in
2600 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
2601 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
2602 * mode, otherwise the operating mode is undefined.
2603 */
2604#define TOTEMPOLE 0x02
2605
2606/*
2607 * Bit 0 can be used to change the Int Pin for the Function. The value is
2608 * 0 by default for both Functions with Function 0 using INT A and Function
2609 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
2610 * INT A is used.
2611 *
2612 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
2613 * value specified in the PCI Configuration Space.
2614 */
2615#define INTAB 0x01
2616
2617/* a_advlib.h */
2618
2619/*
2620 * Adv Library Status Definitions
2621 */
2622#define ADV_TRUE 1
2623#define ADV_FALSE 0
2624#define ADV_NOERROR 1
2625#define ADV_SUCCESS 1
2626#define ADV_BUSY 0
2627#define ADV_ERROR (-1)
2628
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629/*
2630 * ADV_DVC_VAR 'warn_code' values
2631 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002632#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
2633#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
2634#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
2635#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
2636#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002638#define ADV_MAX_TID 15 /* max. target identifier */
2639#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
2641/*
2642 * Error code values are set in ADV_DVC_VAR 'err_code'.
2643 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002644#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
2645#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
2646#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
2647#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
2648#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
2649#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
2650#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
2651#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
2652#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
2653#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
2654#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
2655#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
2656#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
2657#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658
2659/*
2660 * Fixed locations of microcode operating variables.
2661 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002662#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
2663#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
2664#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
2665#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
2666#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
2667#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
2668#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
2669#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
2670#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
2671#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
2672#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
2673#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
2674#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675#define ASC_MC_CHIP_TYPE 0x009A
2676#define ASC_MC_INTRB_CODE 0x009B
2677#define ASC_MC_WDTR_ABLE 0x009C
2678#define ASC_MC_SDTR_ABLE 0x009E
2679#define ASC_MC_TAGQNG_ABLE 0x00A0
2680#define ASC_MC_DISC_ENABLE 0x00A2
2681#define ASC_MC_IDLE_CMD_STATUS 0x00A4
2682#define ASC_MC_IDLE_CMD 0x00A6
2683#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
2684#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
2685#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
2686#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
2687#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
2688#define ASC_MC_SDTR_DONE 0x00B6
2689#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
2690#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
2691#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002692#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002694#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695#define ASC_MC_ICQ 0x0160
2696#define ASC_MC_IRQ 0x0164
2697#define ASC_MC_PPR_ABLE 0x017A
2698
2699/*
2700 * BIOS LRAM variable absolute offsets.
2701 */
2702#define BIOS_CODESEG 0x54
2703#define BIOS_CODELEN 0x56
2704#define BIOS_SIGNATURE 0x58
2705#define BIOS_VERSION 0x5A
2706
2707/*
2708 * Microcode Control Flags
2709 *
2710 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
2711 * and handled by the microcode.
2712 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002713#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
2714#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715
2716/*
2717 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
2718 */
2719#define HSHK_CFG_WIDE_XFR 0x8000
2720#define HSHK_CFG_RATE 0x0F00
2721#define HSHK_CFG_OFFSET 0x001F
2722
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002723#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
2724#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
2725#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
2726#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002728#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2729#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2730#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2731#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2732#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002734#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2735#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2736#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2737#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2738#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739/*
2740 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2741 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2742 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002743#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2744#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
2746/*
2747 * All fields here are accessed by the board microcode and need to be
2748 * little-endian.
2749 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002750typedef struct adv_carr_t {
2751 ADV_VADDR carr_va; /* Carrier Virtual Address */
2752 ADV_PADDR carr_pa; /* Carrier Physical Address */
2753 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2754 /*
2755 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2756 *
2757 * next_vpa [3:1] Reserved Bits
2758 * next_vpa [0] Done Flag set in Response Queue.
2759 */
2760 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761} ADV_CARR_T;
2762
2763/*
2764 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2765 */
2766#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2767
2768#define ASC_RQ_DONE 0x00000001
2769#define ASC_RQ_GOOD 0x00000002
2770#define ASC_CQ_STOPPER 0x00000000
2771
2772#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2773
2774#define ADV_CARRIER_NUM_PAGE_CROSSING \
2775 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2776 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2777
2778#define ADV_CARRIER_BUFSIZE \
2779 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2780
2781/*
2782 * ASC_SCSI_REQ_Q 'a_flag' definitions
2783 *
2784 * The Adv Library should limit use to the lower nibble (4 bits) of
2785 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2786 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002787#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2788#define ADV_SCSIQ_DONE 0x02 /* request done */
2789#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002791#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2792#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2793#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794
2795/*
2796 * Adapter temporary configuration structure
2797 *
2798 * This structure can be discarded after initialization. Don't add
2799 * fields here needed after initialization.
2800 *
2801 * Field naming convention:
2802 *
2803 * *_enable indicates the field enables or disables a feature. The
2804 * value of the field is never reset.
2805 */
2806typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002807 ushort disc_enable; /* enable disconnection */
2808 uchar chip_version; /* chip version */
2809 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2810 ushort lib_version; /* Adv Library version number */
2811 ushort control_flag; /* Microcode Control Flag */
2812 ushort mcode_date; /* Microcode date */
2813 ushort mcode_version; /* Microcode version */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002814 ushort serial1; /* EEPROM serial number word 1 */
2815 ushort serial2; /* EEPROM serial number word 2 */
2816 ushort serial3; /* EEPROM serial number word 3 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817} ADV_DVC_CFG;
2818
2819struct adv_dvc_var;
2820struct adv_scsi_req_q;
2821
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822/*
2823 * Adapter operation variable structure.
2824 *
2825 * One structure is required per host adapter.
2826 *
2827 * Field naming convention:
2828 *
2829 * *_able indicates both whether a feature should be enabled or disabled
2830 * and whether a device isi capable of the feature. At initialization
2831 * this field may be set, but later if a device is found to be incapable
2832 * of the feature, the field is cleared.
2833 */
2834typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002835 AdvPortAddr iop_base; /* I/O port address */
2836 ushort err_code; /* fatal error code */
2837 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002838 ushort wdtr_able; /* try WDTR for a device */
2839 ushort sdtr_able; /* try SDTR for a device */
2840 ushort ultra_able; /* try SDTR Ultra speed for a device */
2841 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2842 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2843 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2844 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2845 ushort tagqng_able; /* try tagged queuing with a device */
2846 ushort ppr_able; /* PPR message capable per TID bitmask. */
2847 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2848 ushort start_motor; /* start motor command allowed */
2849 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2850 uchar chip_no; /* should be assigned by caller */
2851 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2852 uchar irq_no; /* IRQ number */
2853 ushort no_scam; /* scam_tolerant of EEPROM */
2854 struct asc_board *drv_ptr; /* driver pointer to private structure */
2855 uchar chip_scsi_id; /* chip SCSI target ID */
2856 uchar chip_type;
2857 uchar bist_err_code;
2858 ADV_CARR_T *carrier_buf;
2859 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2860 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2861 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2862 ushort carr_pending_cnt; /* Count of pending carriers. */
2863 /*
2864 * Note: The following fields will not be used after initialization. The
2865 * driver may discard the buffer after initialization is done.
2866 */
2867 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868} ADV_DVC_VAR;
2869
2870#define NO_OF_SG_PER_BLOCK 15
2871
2872typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002873 uchar reserved1;
2874 uchar reserved2;
2875 uchar reserved3;
2876 uchar sg_cnt; /* Valid entries in block. */
2877 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
2878 struct {
2879 ADV_PADDR sg_addr; /* SG element address. */
2880 ADV_DCNT sg_count; /* SG element count. */
2881 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882} ADV_SG_BLOCK;
2883
2884/*
2885 * ADV_SCSI_REQ_Q - microcode request structure
2886 *
2887 * All fields in this structure up to byte 60 are used by the microcode.
2888 * The microcode makes assumptions about the size and ordering of fields
2889 * in this structure. Do not change the structure definition here without
2890 * coordinating the change with the microcode.
2891 *
2892 * All fields accessed by microcode must be maintained in little_endian
2893 * order.
2894 */
2895typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002896 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
2897 uchar target_cmd;
2898 uchar target_id; /* Device target identifier. */
2899 uchar target_lun; /* Device target logical unit number. */
2900 ADV_PADDR data_addr; /* Data buffer physical address. */
2901 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
2902 ADV_PADDR sense_addr;
2903 ADV_PADDR carr_pa;
2904 uchar mflag;
2905 uchar sense_len;
2906 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
2907 uchar scsi_cntl;
2908 uchar done_status; /* Completion status. */
2909 uchar scsi_status; /* SCSI status byte. */
2910 uchar host_status; /* Ucode host status. */
2911 uchar sg_working_ix;
2912 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
2913 ADV_PADDR sg_real_addr; /* SG list physical address. */
2914 ADV_PADDR scsiq_rptr;
2915 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
2916 ADV_VADDR scsiq_ptr;
2917 ADV_VADDR carr_va;
2918 /*
2919 * End of microcode structure - 60 bytes. The rest of the structure
2920 * is used by the Adv Library and ignored by the microcode.
2921 */
2922 ADV_VADDR srb_ptr;
2923 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
2924 char *vdata_addr; /* Data buffer virtual address. */
2925 uchar a_flag;
2926 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927} ADV_SCSI_REQ_Q;
2928
2929/*
2930 * Microcode idle loop commands
2931 */
2932#define IDLE_CMD_COMPLETED 0
2933#define IDLE_CMD_STOP_CHIP 0x0001
2934#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
2935#define IDLE_CMD_SEND_INT 0x0004
2936#define IDLE_CMD_ABORT 0x0008
2937#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002938#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
2939#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940#define IDLE_CMD_SCSIREQ 0x0080
2941
2942#define IDLE_CMD_STATUS_SUCCESS 0x0001
2943#define IDLE_CMD_STATUS_FAILURE 0x0002
2944
2945/*
2946 * AdvSendIdleCmd() flag definitions.
2947 */
2948#define ADV_NOWAIT 0x01
2949
2950/*
2951 * Wait loop time out values.
2952 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002953#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
2954#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
2955#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
2956#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
2957#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002959#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
2960#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
2961#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
2962#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002964#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965
2966/*
2967 * Device drivers must define the following functions.
2968 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002969static inline ulong DvcEnterCritical(void);
2970static inline void DvcLeaveCritical(ulong);
2971static void DvcSleepMilliSecond(ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002972static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
2973 uchar *, ASC_SDCNT *, int);
2974static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975
2976/*
2977 * Adv Library functions available to drivers.
2978 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002979static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
2980static int AdvISR(ADV_DVC_VAR *);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002981static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
2982static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
2983static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
2984static int AdvResetChipAndSB(ADV_DVC_VAR *);
2985static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986
2987/*
2988 * Internal Adv Library functions.
2989 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002990static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002991static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
2992static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
2993static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
2994static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
2995static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
2996static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
2997static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
2998static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
2999static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3000static void AdvWaitEEPCmd(AdvPortAddr);
3001static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003/* Read byte from a register. */
3004#define AdvReadByteRegister(iop_base, reg_off) \
3005 (ADV_MEM_READB((iop_base) + (reg_off)))
3006
3007/* Write byte to a register. */
3008#define AdvWriteByteRegister(iop_base, reg_off, byte) \
3009 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
3010
3011/* Read word (2 bytes) from a register. */
3012#define AdvReadWordRegister(iop_base, reg_off) \
3013 (ADV_MEM_READW((iop_base) + (reg_off)))
3014
3015/* Write word (2 bytes) to a register. */
3016#define AdvWriteWordRegister(iop_base, reg_off, word) \
3017 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
3018
3019/* Write dword (4 bytes) to a register. */
3020#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
3021 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
3022
3023/* Read byte from LRAM. */
3024#define AdvReadByteLram(iop_base, addr, byte) \
3025do { \
3026 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3027 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
3028} while (0)
3029
3030/* Write byte to LRAM. */
3031#define AdvWriteByteLram(iop_base, addr, byte) \
3032 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3033 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
3034
3035/* Read word (2 bytes) from LRAM. */
3036#define AdvReadWordLram(iop_base, addr, word) \
3037do { \
3038 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3039 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
3040} while (0)
3041
3042/* Write word (2 bytes) to LRAM. */
3043#define AdvWriteWordLram(iop_base, addr, word) \
3044 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3045 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3046
3047/* Write little-endian double word (4 bytes) to LRAM */
3048/* Because of unspecified C language ordering don't use auto-increment. */
3049#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
3050 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3051 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3052 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
3053 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
3054 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3055 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
3056
3057/* Read word (2 bytes) from LRAM assuming that the address is already set. */
3058#define AdvReadWordAutoIncLram(iop_base) \
3059 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
3060
3061/* Write word (2 bytes) to LRAM assuming that the address is already set. */
3062#define AdvWriteWordAutoIncLram(iop_base, word) \
3063 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3064
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065/*
3066 * Define macro to check for Condor signature.
3067 *
3068 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
3069 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
3070 */
3071#define AdvFindSignature(iop_base) \
3072 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
3073 ADV_CHIP_ID_BYTE) && \
3074 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
3075 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
3076
3077/*
3078 * Define macro to Return the version number of the chip at 'iop_base'.
3079 *
3080 * The second parameter 'bus_type' is currently unused.
3081 */
3082#define AdvGetChipVersion(iop_base, bus_type) \
3083 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
3084
3085/*
3086 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
3087 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
3088 *
3089 * If the request has not yet been sent to the device it will simply be
3090 * aborted from RISC memory. If the request is disconnected it will be
3091 * aborted on reselection by sending an Abort Message to the target ID.
3092 *
3093 * Return value:
3094 * ADV_TRUE(1) - Queue was successfully aborted.
3095 * ADV_FALSE(0) - Queue was not found on the active queue list.
3096 */
3097#define AdvAbortQueue(asc_dvc, scsiq) \
3098 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
3099 (ADV_DCNT) (scsiq))
3100
3101/*
3102 * Send a Bus Device Reset Message to the specified target ID.
3103 *
3104 * All outstanding commands will be purged if sending the
3105 * Bus Device Reset Message is successful.
3106 *
3107 * Return Value:
3108 * ADV_TRUE(1) - All requests on the target are purged.
3109 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
3110 * are not purged.
3111 */
3112#define AdvResetDevice(asc_dvc, target_id) \
3113 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
3114 (ADV_DCNT) (target_id))
3115
3116/*
3117 * SCSI Wide Type definition.
3118 */
3119#define ADV_SCSI_BIT_ID_TYPE ushort
3120
3121/*
3122 * AdvInitScsiTarget() 'cntl_flag' options.
3123 */
3124#define ADV_SCAN_LUN 0x01
3125#define ADV_CAPINFO_NOLUN 0x02
3126
3127/*
3128 * Convert target id to target id bit mask.
3129 */
3130#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
3131
3132/*
3133 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
3134 */
3135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003136#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137#define QD_NO_ERROR 0x01
3138#define QD_ABORTED_BY_HOST 0x02
3139#define QD_WITH_ERROR 0x04
3140
3141#define QHSTA_NO_ERROR 0x00
3142#define QHSTA_M_SEL_TIMEOUT 0x11
3143#define QHSTA_M_DATA_OVER_RUN 0x12
3144#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
3145#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003146#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
3147#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
3148#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
3149#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
3150#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
3151#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
3152#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003154#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
3155#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
3156#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
3157#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
3158#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
3159#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
3160#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
3161#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162#define QHSTA_M_WTM_TIMEOUT 0x41
3163#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
3164#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
3165#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003166#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
3167#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
3168#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
3170/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 * DvcGetPhyAddr() flag arguments
3172 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003173#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
3174#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
3175#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
3176#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
3177#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
3178#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179
3180/* Return the address that is aligned at the next doubleword >= to 'addr'. */
3181#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
3182#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
3183#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
3184
3185/*
3186 * Total contiguous memory needed for driver SG blocks.
3187 *
3188 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
3189 * number of scatter-gather elements the driver supports in a
3190 * single request.
3191 */
3192
3193#define ADV_SG_LIST_MAX_BYTE_SIZE \
3194 (sizeof(ADV_SG_BLOCK) * \
3195 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
3196
3197/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198 * --- Driver Constants and Macros
3199 */
3200
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201/* Reference Scsi_Host hostdata */
3202#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
3203
3204/* asc_board_t flags */
3205#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003206#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207#define ASC_SELECT_QUEUE_DEPTHS 0x08
3208
3209#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
3210#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
3211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003212#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003214#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215
3216#ifdef CONFIG_PROC_FS
3217/* /proc/scsi/advansys/[0...] related definitions */
3218#define ASC_PRTBUF_SIZE 2048
3219#define ASC_PRTLINE_SIZE 160
3220
3221#define ASC_PRT_NEXT() \
3222 if (cp) { \
3223 totlen += len; \
3224 leftlen -= len; \
3225 if (leftlen == 0) { \
3226 return totlen; \
3227 } \
3228 cp += len; \
3229 }
3230#endif /* CONFIG_PROC_FS */
3231
3232/* Asc Library return codes */
3233#define ASC_TRUE 1
3234#define ASC_FALSE 0
3235#define ASC_NOERROR 1
3236#define ASC_BUSY 0
3237#define ASC_ERROR (-1)
3238
3239/* struct scsi_cmnd function return codes */
3240#define STATUS_BYTE(byte) (byte)
3241#define MSG_BYTE(byte) ((byte) << 8)
3242#define HOST_BYTE(byte) ((byte) << 16)
3243#define DRIVER_BYTE(byte) ((byte) << 24)
3244
3245/*
3246 * The following definitions and macros are OS independent interfaces to
3247 * the queue functions:
3248 * REQ - SCSI request structure
3249 * REQP - pointer to SCSI request structure
3250 * REQPTID(reqp) - reqp's target id
3251 * REQPNEXT(reqp) - reqp's next pointer
3252 * REQPNEXTP(reqp) - pointer to reqp's next pointer
3253 * REQPTIME(reqp) - reqp's time stamp value
3254 * REQTIMESTAMP() - system time stamp value
3255 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003256typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
3258#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
3259#define REQPTID(reqp) ((reqp)->device->id)
3260#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
3261#define REQTIMESTAMP() (jiffies)
3262
3263#define REQTIMESTAT(function, ascq, reqp, tid) \
3264{ \
3265 /*
3266 * If the request time stamp is less than the system time stamp, then \
3267 * maybe the system time stamp wrapped. Set the request time to zero.\
3268 */ \
3269 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
3270 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
3271 } else { \
3272 /* Indicate an error occurred with the assertion. */ \
3273 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
3274 REQPTIME(reqp) = 0; \
3275 } \
3276 /* Handle first minimum time case without external initialization. */ \
3277 if (((ascq)->q_tot_cnt[tid] == 1) || \
3278 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
3279 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
3280 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
3281 (function), (tid), (ascq)->q_min_tim[tid]); \
3282 } \
3283 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
3284 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
3285 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
3286 (function), tid, (ascq)->q_max_tim[tid]); \
3287 } \
3288 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
3289 /* Reset the time stamp field. */ \
3290 REQPTIME(reqp) = 0; \
3291}
3292
3293/* asc_enqueue() flags */
3294#define ASC_FRONT 1
3295#define ASC_BACK 2
3296
3297/* asc_dequeue_list() argument */
3298#define ASC_TID_ALL (-1)
3299
3300/* Return non-zero, if the queue is empty. */
3301#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
3302
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003304#define ASC_STATS(shost, counter)
3305#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003307#define ASC_STATS(shost, counter) \
3308 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003310#define ASC_STATS_ADD(shost, counter, count) \
3311 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312#endif /* ADVANSYS_STATS */
3313
3314#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
3315
3316/* If the result wraps when calculating tenths, return 0. */
3317#define ASC_TENTHS(num, den) \
3318 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
3319 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
3320
3321/*
3322 * Display a message to the console.
3323 */
3324#define ASC_PRINT(s) \
3325 { \
3326 printk("advansys: "); \
3327 printk(s); \
3328 }
3329
3330#define ASC_PRINT1(s, a1) \
3331 { \
3332 printk("advansys: "); \
3333 printk((s), (a1)); \
3334 }
3335
3336#define ASC_PRINT2(s, a1, a2) \
3337 { \
3338 printk("advansys: "); \
3339 printk((s), (a1), (a2)); \
3340 }
3341
3342#define ASC_PRINT3(s, a1, a2, a3) \
3343 { \
3344 printk("advansys: "); \
3345 printk((s), (a1), (a2), (a3)); \
3346 }
3347
3348#define ASC_PRINT4(s, a1, a2, a3, a4) \
3349 { \
3350 printk("advansys: "); \
3351 printk((s), (a1), (a2), (a3), (a4)); \
3352 }
3353
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354#ifndef ADVANSYS_DEBUG
3355
3356#define ASC_DBG(lvl, s)
3357#define ASC_DBG1(lvl, s, a1)
3358#define ASC_DBG2(lvl, s, a1, a2)
3359#define ASC_DBG3(lvl, s, a1, a2, a3)
3360#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
3361#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
3362#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
3363#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
3364#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3365#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
3366#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3367#define ASC_DBG_PRT_HEX(lvl, name, start, length)
3368#define ASC_DBG_PRT_CDB(lvl, cdb, len)
3369#define ASC_DBG_PRT_SENSE(lvl, sense, len)
3370#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
3371
3372#else /* ADVANSYS_DEBUG */
3373
3374/*
3375 * Debugging Message Levels:
3376 * 0: Errors Only
3377 * 1: High-Level Tracing
3378 * 2-N: Verbose Tracing
3379 */
3380
3381#define ASC_DBG(lvl, s) \
3382 { \
3383 if (asc_dbglvl >= (lvl)) { \
3384 printk(s); \
3385 } \
3386 }
3387
3388#define ASC_DBG1(lvl, s, a1) \
3389 { \
3390 if (asc_dbglvl >= (lvl)) { \
3391 printk((s), (a1)); \
3392 } \
3393 }
3394
3395#define ASC_DBG2(lvl, s, a1, a2) \
3396 { \
3397 if (asc_dbglvl >= (lvl)) { \
3398 printk((s), (a1), (a2)); \
3399 } \
3400 }
3401
3402#define ASC_DBG3(lvl, s, a1, a2, a3) \
3403 { \
3404 if (asc_dbglvl >= (lvl)) { \
3405 printk((s), (a1), (a2), (a3)); \
3406 } \
3407 }
3408
3409#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
3410 { \
3411 if (asc_dbglvl >= (lvl)) { \
3412 printk((s), (a1), (a2), (a3), (a4)); \
3413 } \
3414 }
3415
3416#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
3417 { \
3418 if (asc_dbglvl >= (lvl)) { \
3419 asc_prt_scsi_host(s); \
3420 } \
3421 }
3422
3423#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
3424 { \
3425 if (asc_dbglvl >= (lvl)) { \
3426 asc_prt_scsi_cmnd(s); \
3427 } \
3428 }
3429
3430#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
3431 { \
3432 if (asc_dbglvl >= (lvl)) { \
3433 asc_prt_asc_scsi_q(scsiqp); \
3434 } \
3435 }
3436
3437#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
3438 { \
3439 if (asc_dbglvl >= (lvl)) { \
3440 asc_prt_asc_qdone_info(qdone); \
3441 } \
3442 }
3443
3444#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
3445 { \
3446 if (asc_dbglvl >= (lvl)) { \
3447 asc_prt_adv_scsi_req_q(scsiqp); \
3448 } \
3449 }
3450
3451#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
3452 { \
3453 if (asc_dbglvl >= (lvl)) { \
3454 asc_prt_hex((name), (start), (length)); \
3455 } \
3456 }
3457
3458#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
3459 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
3460
3461#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
3462 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
3463
3464#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
3465 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
3466#endif /* ADVANSYS_DEBUG */
3467
3468#ifndef ADVANSYS_ASSERT
3469#define ASC_ASSERT(a)
3470#else /* ADVANSYS_ASSERT */
3471
3472#define ASC_ASSERT(a) \
3473 { \
3474 if (!(a)) { \
3475 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
3476 __FILE__, __LINE__); \
3477 } \
3478 }
3479
3480#endif /* ADVANSYS_ASSERT */
3481
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482/*
3483 * --- Driver Structures
3484 */
3485
3486#ifdef ADVANSYS_STATS
3487
3488/* Per board statistics structure */
3489struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003490 /* Driver Entrypoint Statistics */
3491 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
3492 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
3493 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
3494 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
3495 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
3496 ADV_DCNT done; /* # calls to request's scsi_done function */
3497 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
3498 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
3499 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
3500 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
3501 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
3502 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
3503 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
3504 ADV_DCNT exe_unknown; /* # unknown returns. */
3505 /* Data Transfer Statistics */
3506 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
3507 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
3508 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
3509 ADV_DCNT sg_elem; /* # scatter-gather elements */
3510 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511};
3512#endif /* ADVANSYS_STATS */
3513
3514/*
3515 * Request queuing structure
3516 */
3517typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003518 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
3519 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
3520 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003522 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
3523 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
3524 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
3525 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
3526 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
3527 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
3528#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529} asc_queue_t;
3530
3531/*
3532 * Adv Library Request Structures
3533 *
3534 * The following two structures are used to process Wide Board requests.
3535 *
3536 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
3537 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
3538 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
3539 * Mid-Level SCSI request structure.
3540 *
3541 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
3542 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
3543 * up to 255 scatter-gather elements may be used per request or
3544 * ADV_SCSI_REQ_Q.
3545 *
3546 * Both structures must be 32 byte aligned.
3547 */
3548typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003549 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
3550 uchar align[32]; /* Sgblock structure padding. */
3551 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552} adv_sgblk_t;
3553
3554typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003555 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
3556 uchar align[32]; /* Request structure padding. */
3557 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
3558 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
3559 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560} adv_req_t;
3561
3562/*
3563 * Structure allocated for each board.
3564 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003565 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 * of the 'Scsi_Host' structure starting at the 'hostdata'
3567 * field. It is guaranteed to be allocated from DMA-able memory.
3568 */
3569typedef struct asc_board {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003570 struct device *dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003571 int id; /* Board Id */
3572 uint flags; /* Board flags */
3573 union {
3574 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
3575 ADV_DVC_VAR adv_dvc_var; /* Wide board */
3576 } dvc_var;
3577 union {
3578 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
3579 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
3580 } dvc_cfg;
3581 ushort asc_n_io_port; /* Number I/O ports. */
3582 asc_queue_t active; /* Active command queue */
3583 asc_queue_t waiting; /* Waiting command queue */
3584 asc_queue_t done; /* Done command queue */
3585 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
3586 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
3587 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
3588 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
3589 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
3590 union {
3591 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
3592 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
3593 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
3594 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
3595 } eep_config;
3596 ulong last_reset; /* Saved last reset time */
3597 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003598 /* /proc/scsi/advansys/[0...] */
3599 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003601 struct asc_stats asc_stats; /* Board statistics */
3602#endif /* ADVANSYS_STATS */
3603 /*
3604 * The following fields are used only for Narrow Boards.
3605 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003606 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3607 /*
3608 * The following fields are used only for Wide Boards.
3609 */
3610 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3611 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06003612 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003613 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3614 adv_req_t *adv_reqp; /* Request structures. */
3615 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3616 ushort bios_signature; /* BIOS Signature. */
3617 ushort bios_version; /* BIOS Version. */
3618 ushort bios_codeseg; /* BIOS Code Segment. */
3619 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620} asc_board_t;
3621
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06003622#define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \
3623 dvc_var.adv_dvc_var)
3624#define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev)
3625
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06003627static int asc_board_count;
3628
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003630static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631
3632/*
3633 * Global structures required to issue a command.
3634 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003635static ASC_SCSI_Q asc_scsi_q = { {0} };
3636static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003639static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640#endif /* ADVANSYS_DEBUG */
3641
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642/*
3643 * --- Driver Function Prototypes
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 */
3645
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003646static int advansys_slave_configure(struct scsi_device *);
3647static void asc_scsi_done_list(struct scsi_cmnd *);
3648static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3649static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3650static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3651static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003652static void asc_enqueue(asc_queue_t *, REQP, int);
3653static REQP asc_dequeue(asc_queue_t *, int);
3654static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3655static int asc_rmqueue(asc_queue_t *, REQP);
3656static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003658static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3659static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3660static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3661static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3662static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3663static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3664static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3665static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3666static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3667static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668#endif /* CONFIG_PROC_FS */
3669
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670/* Statistics function prototypes. */
3671#ifdef ADVANSYS_STATS
3672#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003673static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3674static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675#endif /* CONFIG_PROC_FS */
3676#endif /* ADVANSYS_STATS */
3677
3678/* Debug function prototypes. */
3679#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003680static void asc_prt_scsi_host(struct Scsi_Host *);
3681static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
3682static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
3683static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
3684static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
3685static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
3686static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
3687static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
3688static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
3689static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
3690static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691#endif /* ADVANSYS_DEBUG */
3692
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693#ifdef CONFIG_PROC_FS
3694/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06003695 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 *
3697 * *buffer: I/O buffer
3698 * **start: if inout == FALSE pointer into buffer where user read should start
3699 * offset: current offset into a /proc/scsi/advansys/[0...] file
3700 * length: length of buffer
3701 * hostno: Scsi_Host host_no
3702 * inout: TRUE - user is writing; FALSE - user is reading
3703 *
3704 * Return the number of bytes read from or written to a
3705 * /proc/scsi/advansys/[0...] file.
3706 *
3707 * Note: This function uses the per board buffer 'prtbuf' which is
3708 * allocated when the board is initialized in advansys_detect(). The
3709 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
3710 * used to write to the buffer. The way asc_proc_copy() is written
3711 * if 'prtbuf' is too small it will not be overwritten. Instead the
3712 * user just won't get all the available statistics.
3713 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003714static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003716 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003718 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003719 char *cp;
3720 int cplen;
3721 int cnt;
3722 int totcnt;
3723 int leftlen;
3724 char *curbuf;
3725 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003727 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728#endif /* ADVANSYS_STATS */
3729
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003730 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003732 /*
3733 * User write not supported.
3734 */
3735 if (inout == TRUE) {
3736 return (-ENOSYS);
3737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003739 /*
3740 * User read of /proc/scsi/advansys/[0...] file.
3741 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742
Matthew Wilcox2a437952007-07-26 11:00:51 -04003743 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003745 /* Copy read data starting at the beginning of the buffer. */
3746 *start = buffer;
3747 curbuf = buffer;
3748 advoffset = 0;
3749 totcnt = 0;
3750 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003752 /*
3753 * Get board configuration information.
3754 *
3755 * advansys_info() returns the board string from its own static buffer.
3756 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04003757 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003758 strcat(cp, "\n");
3759 cplen = strlen(cp);
3760 /* Copy board information. */
3761 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3762 totcnt += cnt;
3763 leftlen -= cnt;
3764 if (leftlen == 0) {
3765 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3766 return totcnt;
3767 }
3768 advoffset += cplen;
3769 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003771 /*
3772 * Display Wide Board BIOS Information.
3773 */
3774 if (ASC_WIDE_BOARD(boardp)) {
3775 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003776 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003777 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003778 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003779 cplen);
3780 totcnt += cnt;
3781 leftlen -= cnt;
3782 if (leftlen == 0) {
3783 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3784 return totcnt;
3785 }
3786 advoffset += cplen;
3787 curbuf += cnt;
3788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003790 /*
3791 * Display driver information for each device attached to the board.
3792 */
3793 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003794 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003795 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3796 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3797 totcnt += cnt;
3798 leftlen -= cnt;
3799 if (leftlen == 0) {
3800 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3801 return totcnt;
3802 }
3803 advoffset += cplen;
3804 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003806 /*
3807 * Display EEPROM configuration for the board.
3808 */
3809 cp = boardp->prtbuf;
3810 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003811 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003812 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003813 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003814 }
3815 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3816 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3817 totcnt += cnt;
3818 leftlen -= cnt;
3819 if (leftlen == 0) {
3820 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3821 return totcnt;
3822 }
3823 advoffset += cplen;
3824 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003826 /*
3827 * Display driver configuration and information for the board.
3828 */
3829 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003830 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003831 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3832 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3833 totcnt += cnt;
3834 leftlen -= cnt;
3835 if (leftlen == 0) {
3836 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3837 return totcnt;
3838 }
3839 advoffset += cplen;
3840 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841
3842#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003843 /*
3844 * Display driver statistics for the board.
3845 */
3846 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003847 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003848 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
3849 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3850 totcnt += cnt;
3851 leftlen -= cnt;
3852 if (leftlen == 0) {
3853 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3854 return totcnt;
3855 }
3856 advoffset += cplen;
3857 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003859 /*
3860 * Display driver statistics for each target.
3861 */
3862 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
3863 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003864 cplen = asc_prt_target_stats(shost, tgt_id, cp,
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003865 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003866 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003867 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
3868 cplen);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003869 totcnt += cnt;
3870 leftlen -= cnt;
3871 if (leftlen == 0) {
3872 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3873 return totcnt;
3874 }
3875 advoffset += cplen;
3876 curbuf += cnt;
3877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878#endif /* ADVANSYS_STATS */
3879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003880 /*
3881 * Display Asc Library dynamic configuration information
3882 * for the board.
3883 */
3884 cp = boardp->prtbuf;
3885 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003886 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003887 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003888 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003889 }
3890 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3891 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3892 totcnt += cnt;
3893 leftlen -= cnt;
3894 if (leftlen == 0) {
3895 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3896 return totcnt;
3897 }
3898 advoffset += cplen;
3899 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003901 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003903 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904}
3905#endif /* CONFIG_PROC_FS */
3906
3907/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 * advansys_info()
3909 *
3910 * Return suitable for printing on the console with the argument
3911 * adapter's configuration information.
3912 *
3913 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
3914 * otherwise the static 'info' array will be overrun.
3915 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003916static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003918 static char info[ASC_INFO_SIZE];
3919 asc_board_t *boardp;
3920 ASC_DVC_VAR *asc_dvc_varp;
3921 ADV_DVC_VAR *adv_dvc_varp;
3922 char *busname;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003923 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003925 boardp = ASC_BOARDP(shost);
3926 if (ASC_NARROW_BOARD(boardp)) {
3927 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
3928 ASC_DBG(1, "advansys_info: begin\n");
3929 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
3930 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
3931 ASC_IS_ISAPNP) {
3932 busname = "ISA PnP";
3933 } else {
3934 busname = "ISA";
3935 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003936 sprintf(info,
3937 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
3938 ASC_VERSION, busname,
3939 (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003940 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3941 shost->irq, shost->dma_channel);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003942 } else {
3943 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
3944 busname = "VL";
3945 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
3946 busname = "EISA";
3947 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
3948 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
3949 == ASC_IS_PCI_ULTRA) {
3950 busname = "PCI Ultra";
3951 } else {
3952 busname = "PCI";
3953 }
3954 } else {
3955 busname = "?";
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003956 ASC_PRINT2("advansys_info: board %d: unknown "
3957 "bus type %d\n", boardp->id,
3958 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003959 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003960 sprintf(info,
3961 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003962 ASC_VERSION, busname, (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003963 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3964 shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003965 }
3966 } else {
3967 /*
3968 * Wide Adapter Information
3969 *
3970 * Memory-mapped I/O is used instead of I/O space to access
3971 * the adapter, but display the I/O Port range. The Memory
3972 * I/O address is displayed through the driver /proc file.
3973 */
3974 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
3975 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003976 widename = "Ultra-Wide";
3977 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003978 widename = "Ultra2-Wide";
3979 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003980 widename = "Ultra3-Wide";
3981 }
3982 sprintf(info,
3983 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
3984 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003985 (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003986 }
3987 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
3988 ASC_DBG(1, "advansys_info: end\n");
3989 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990}
3991
3992/*
3993 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
3994 *
3995 * This function always returns 0. Command return status is saved
3996 * in the 'scp' result field.
3997 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003998static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003999advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004001 struct Scsi_Host *shost;
4002 asc_board_t *boardp;
4003 ulong flags;
4004 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004006 shost = scp->device->host;
4007 boardp = ASC_BOARDP(shost);
4008 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004010 /* host_lock taken by mid-level prior to call but need to protect */
4011 /* against own ISR */
4012 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004014 /*
4015 * Block new commands while handling a reset or abort request.
4016 */
4017 if (boardp->flags & ASC_HOST_IN_RESET) {
4018 ASC_DBG1(1,
4019 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4020 (ulong)scp);
4021 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004023 /*
4024 * Add blocked requests to the board's 'done' queue. The queued
4025 * requests will be completed at the end of the abort or reset
4026 * handling.
4027 */
4028 asc_enqueue(&boardp->done, scp, ASC_BACK);
4029 spin_unlock_irqrestore(&boardp->lock, flags);
4030 return 0;
4031 }
4032
4033 /*
4034 * Attempt to execute any waiting commands for the board.
4035 */
4036 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4037 ASC_DBG(1,
4038 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4039 asc_execute_queue(&boardp->waiting);
4040 }
4041
4042 /*
4043 * Save the function pointer to Linux mid-level 'done' function
4044 * and attempt to execute the command.
4045 *
4046 * If ASC_NOERROR is returned the request has been added to the
4047 * board's 'active' queue and will be completed by the interrupt
4048 * handler.
4049 *
4050 * If ASC_BUSY is returned add the request to the board's per
4051 * target waiting list. This is the first time the request has
4052 * been tried. Add it to the back of the waiting list. It will be
4053 * retried later.
4054 *
4055 * If an error occurred, the request will have been placed on the
4056 * board's 'done' queue and must be completed before returning.
4057 */
4058 scp->scsi_done = done;
4059 switch (asc_execute_scsi_cmnd(scp)) {
4060 case ASC_NOERROR:
4061 break;
4062 case ASC_BUSY:
4063 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4064 break;
4065 case ASC_ERROR:
4066 default:
4067 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4068 /* Interrupts could be enabled here. */
4069 asc_scsi_done_list(done_scp);
4070 break;
4071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004074 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075}
4076
4077/*
4078 * advansys_reset()
4079 *
4080 * Reset the bus associated with the command 'scp'.
4081 *
4082 * This function runs its own thread. Interrupts must be blocked but
4083 * sleeping is allowed and no locking other than for host structures is
4084 * required. Returns SUCCESS or FAILED.
4085 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004086static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004088 struct Scsi_Host *shost;
4089 asc_board_t *boardp;
4090 ASC_DVC_VAR *asc_dvc_varp;
4091 ADV_DVC_VAR *adv_dvc_varp;
4092 ulong flags;
4093 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4094 struct scsi_cmnd *tscp, *new_last_scp;
4095 int status;
4096 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004098 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099
4100#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004101 if (scp->device->host != NULL) {
4102 ASC_STATS(scp->device->host, reset);
4103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104#endif /* ADVANSYS_STATS */
4105
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004106 if ((shost = scp->device->host) == NULL) {
4107 scp->result = HOST_BYTE(DID_ERROR);
4108 return FAILED;
4109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004111 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004113 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4114 boardp->id);
4115 /*
4116 * Check for re-entrancy.
4117 */
4118 spin_lock_irqsave(&boardp->lock, flags);
4119 if (boardp->flags & ASC_HOST_IN_RESET) {
4120 spin_unlock_irqrestore(&boardp->lock, flags);
4121 return FAILED;
4122 }
4123 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004126 if (ASC_NARROW_BOARD(boardp)) {
4127 /*
4128 * Narrow Board
4129 */
4130 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004132 /*
4133 * Reset the chip and SCSI bus.
4134 */
4135 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4136 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004138 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4139 if (asc_dvc_varp->err_code) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004140 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4141 "error: 0x%x\n", boardp->id,
4142 asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004143 ret = FAILED;
4144 } else if (status) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004145 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4146 "warning: 0x%x\n", boardp->id, status);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004147 } else {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004148 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4149 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004152 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4153 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004155 } else {
4156 /*
4157 * Wide Board
4158 *
4159 * If the suggest reset bus flags are set, then reset the bus.
4160 * Otherwise only reset the device.
4161 */
4162 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004164 /*
4165 * Reset the target's SCSI bus.
4166 */
4167 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4168 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4169 case ASC_TRUE:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004170 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4171 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004172 break;
4173 case ASC_FALSE:
4174 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004175 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4176 "error.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004177 ret = FAILED;
4178 break;
4179 }
4180 spin_lock_irqsave(&boardp->lock, flags);
4181 (void)AdvISR(adv_dvc_varp);
4182 }
4183 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004185 /*
4186 * Dequeue all board 'done' requests. A pointer to the last request
4187 * is returned in 'last_scp'.
4188 */
4189 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004191 /*
4192 * Dequeue all board 'active' requests for all devices and set
4193 * the request status to DID_RESET. A pointer to the last request
4194 * is returned in 'last_scp'.
4195 */
4196 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004197 done_scp = asc_dequeue_list(&boardp->active, &last_scp,
4198 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004199 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4200 tscp->result = HOST_BYTE(DID_RESET);
4201 }
4202 } else {
4203 /* Append to 'done_scp' at the end with 'last_scp'. */
4204 ASC_ASSERT(last_scp != NULL);
4205 last_scp->host_scribble =
4206 (unsigned char *)asc_dequeue_list(&boardp->active,
4207 &new_last_scp,
4208 ASC_TID_ALL);
4209 if (new_last_scp != NULL) {
4210 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4211 for (tscp = REQPNEXT(last_scp); tscp;
4212 tscp = REQPNEXT(tscp)) {
4213 tscp->result = HOST_BYTE(DID_RESET);
4214 }
4215 last_scp = new_last_scp;
4216 }
4217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004219 /*
4220 * Dequeue all 'waiting' requests and set the request status
4221 * to DID_RESET.
4222 */
4223 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004224 done_scp = asc_dequeue_list(&boardp->waiting, &last_scp,
4225 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004226 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4227 tscp->result = HOST_BYTE(DID_RESET);
4228 }
4229 } else {
4230 /* Append to 'done_scp' at the end with 'last_scp'. */
4231 ASC_ASSERT(last_scp != NULL);
4232 last_scp->host_scribble =
4233 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4234 &new_last_scp,
4235 ASC_TID_ALL);
4236 if (new_last_scp != NULL) {
4237 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4238 for (tscp = REQPNEXT(last_scp); tscp;
4239 tscp = REQPNEXT(tscp)) {
4240 tscp->result = HOST_BYTE(DID_RESET);
4241 }
4242 last_scp = new_last_scp;
4243 }
4244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004246 /* Save the time of the most recently completed reset. */
4247 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004249 /* Clear reset flag. */
4250 boardp->flags &= ~ASC_HOST_IN_RESET;
4251 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004253 /*
4254 * Complete all the 'done_scp' requests.
4255 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004256 if (done_scp)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004257 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004259 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004261 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262}
4263
4264/*
4265 * advansys_biosparam()
4266 *
4267 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4268 * support is enabled for a drive.
4269 *
4270 * ip (information pointer) is an int array with the following definition:
4271 * ip[0]: heads
4272 * ip[1]: sectors
4273 * ip[2]: cylinders
4274 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004275static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004277 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004279 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004281 ASC_DBG(1, "advansys_biosparam: begin\n");
4282 ASC_STATS(sdev->host, biosparam);
4283 boardp = ASC_BOARDP(sdev->host);
4284 if (ASC_NARROW_BOARD(boardp)) {
4285 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4286 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4287 ip[0] = 255;
4288 ip[1] = 63;
4289 } else {
4290 ip[0] = 64;
4291 ip[1] = 32;
4292 }
4293 } else {
4294 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4295 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4296 ip[0] = 255;
4297 ip[1] = 63;
4298 } else {
4299 ip[0] = 64;
4300 ip[1] = 32;
4301 }
4302 }
4303 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4304 ASC_DBG(1, "advansys_biosparam: end\n");
4305 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306}
4307
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004308static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004309 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004311 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004313 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004314 .info = advansys_info,
4315 .queuecommand = advansys_queuecommand,
4316 .eh_bus_reset_handler = advansys_reset,
4317 .bios_param = advansys_biosparam,
4318 .slave_configure = advansys_slave_configure,
4319 /*
4320 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004321 * must be set. The flag will be cleared in advansys_board_found
4322 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004323 */
4324 .unchecked_isa_dma = 1,
4325 /*
4326 * All adapters controlled by this driver are capable of large
4327 * scatter-gather lists. According to the mid-level SCSI documentation
4328 * this obviates any performance gain provided by setting
4329 * 'use_clustering'. But empirically while CPU utilization is increased
4330 * by enabling clustering, I/O throughput increases as well.
4331 */
4332 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335/*
4336 * --- Miscellaneous Driver Functions
4337 */
4338
4339/*
4340 * First-level interrupt handler.
4341 *
4342 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4343 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4344 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4345 * to the AdvanSys driver which is for a device sharing an interrupt with
4346 * an AdvanSys adapter.
4347 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004348static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004350 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004351 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4352 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004353 struct Scsi_Host *shost = dev_id;
4354 asc_board_t *boardp = ASC_BOARDP(shost);
4355 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004357 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
4358 spin_lock_irqsave(&boardp->lock, flags);
4359 if (ASC_NARROW_BOARD(boardp)) {
4360 /*
4361 * Narrow Board
4362 */
4363 if (AscIsIntPending(shost->io_port)) {
4364 result = IRQ_HANDLED;
4365 ASC_STATS(shost, interrupt);
4366 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
4367 AscISR(&boardp->dvc_var.asc_dvc_var);
4368 }
4369 } else {
4370 /*
4371 * Wide Board
4372 */
4373 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4374 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4375 result = IRQ_HANDLED;
4376 ASC_STATS(shost, interrupt);
4377 }
4378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004380 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004381 * Start waiting requests and create a list of completed requests.
4382 *
4383 * If a reset request is being performed for the board, the reset
4384 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004385 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004386 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4387 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
4388 "last_scp 0x%p\n", done_scp, last_scp);
4389
4390 /* Start any waiting commands for the board. */
4391 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4392 ASC_DBG(1, "advansys_interrupt: before "
4393 "asc_execute_queue()\n");
4394 asc_execute_queue(&boardp->waiting);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004397 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004398 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004399 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004400 * 'done_scp' will always be NULL on the first iteration of
4401 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004402 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004403 if (done_scp == NULL) {
4404 done_scp = asc_dequeue_list(&boardp->done,
4405 &last_scp, ASC_TID_ALL);
4406 } else {
4407 ASC_ASSERT(last_scp != NULL);
4408 last_scp->host_scribble =
4409 (unsigned char *)asc_dequeue_list(&boardp->
4410 done,
4411 &new_last_scp,
4412 ASC_TID_ALL);
4413 if (new_last_scp != NULL) {
4414 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4415 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004416 }
4417 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004418 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004419 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004421 /*
4422 * If interrupts were enabled on entry, then they
4423 * are now enabled here.
4424 *
4425 * Complete all requests on the done list.
4426 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004428 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004430 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004431 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432}
4433
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004434static void
4435advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
4436{
4437 ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
4438 ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
4439
4440 if (sdev->lun == 0) {
4441 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
4442 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
4443 asc_dvc->init_sdtr |= tid_bit;
4444 } else {
4445 asc_dvc->init_sdtr &= ~tid_bit;
4446 }
4447
4448 if (orig_init_sdtr != asc_dvc->init_sdtr)
4449 AscAsyncFix(asc_dvc, sdev);
4450 }
4451
4452 if (sdev->tagged_supported) {
4453 if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
4454 if (sdev->lun == 0) {
4455 asc_dvc->cfg->can_tagged_qng |= tid_bit;
4456 asc_dvc->use_tagged_qng |= tid_bit;
4457 }
4458 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4459 asc_dvc->max_dvc_qng[sdev->id]);
4460 }
4461 } else {
4462 if (sdev->lun == 0) {
4463 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
4464 asc_dvc->use_tagged_qng &= ~tid_bit;
4465 }
4466 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4467 }
4468
4469 if ((sdev->lun == 0) &&
4470 (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
4471 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
4472 asc_dvc->cfg->disc_enable);
4473 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
4474 asc_dvc->use_tagged_qng);
4475 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
4476 asc_dvc->cfg->can_tagged_qng);
4477
4478 asc_dvc->max_dvc_qng[sdev->id] =
4479 asc_dvc->cfg->max_tag_qng[sdev->id];
4480 AscWriteLramByte(asc_dvc->iop_base,
4481 (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
4482 asc_dvc->max_dvc_qng[sdev->id]);
4483 }
4484}
4485
4486/*
4487 * Wide Transfers
4488 *
4489 * If the EEPROM enabled WDTR for the device and the device supports wide
4490 * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
4491 * write the new value to the microcode.
4492 */
4493static void
4494advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
4495{
4496 unsigned short cfg_word;
4497 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4498 if ((cfg_word & tidmask) != 0)
4499 return;
4500
4501 cfg_word |= tidmask;
4502 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4503
4504 /*
4505 * Clear the microcode SDTR and WDTR negotiation done indicators for
4506 * the target to cause it to negotiate with the new setting set above.
4507 * WDTR when accepted causes the target to enter asynchronous mode, so
4508 * SDTR must be negotiated.
4509 */
4510 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4511 cfg_word &= ~tidmask;
4512 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4513 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4514 cfg_word &= ~tidmask;
4515 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4516}
4517
4518/*
4519 * Synchronous Transfers
4520 *
4521 * If the EEPROM enabled SDTR for the device and the device
4522 * supports synchronous transfers, then turn on the device's
4523 * 'sdtr_able' bit. Write the new value to the microcode.
4524 */
4525static void
4526advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
4527{
4528 unsigned short cfg_word;
4529 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4530 if ((cfg_word & tidmask) != 0)
4531 return;
4532
4533 cfg_word |= tidmask;
4534 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4535
4536 /*
4537 * Clear the microcode "SDTR negotiation" done indicator for the
4538 * target to cause it to negotiate with the new setting set above.
4539 */
4540 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4541 cfg_word &= ~tidmask;
4542 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4543}
4544
4545/*
4546 * PPR (Parallel Protocol Request) Capable
4547 *
4548 * If the device supports DT mode, then it must be PPR capable.
4549 * The PPR message will be used in place of the SDTR and WDTR
4550 * messages to negotiate synchronous speed and offset, transfer
4551 * width, and protocol options.
4552 */
4553static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
4554 AdvPortAddr iop_base, unsigned short tidmask)
4555{
4556 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4557 adv_dvc->ppr_able |= tidmask;
4558 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4559}
4560
4561static void
4562advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
4563{
4564 AdvPortAddr iop_base = adv_dvc->iop_base;
4565 unsigned short tidmask = 1 << sdev->id;
4566
4567 if (sdev->lun == 0) {
4568 /*
4569 * Handle WDTR, SDTR, and Tag Queuing. If the feature
4570 * is enabled in the EEPROM and the device supports the
4571 * feature, then enable it in the microcode.
4572 */
4573
4574 if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
4575 advansys_wide_enable_wdtr(iop_base, tidmask);
4576 if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
4577 advansys_wide_enable_sdtr(iop_base, tidmask);
4578 if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
4579 advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
4580
4581 /*
4582 * Tag Queuing is disabled for the BIOS which runs in polled
4583 * mode and would see no benefit from Tag Queuing. Also by
4584 * disabling Tag Queuing in the BIOS devices with Tag Queuing
4585 * bugs will at least work with the BIOS.
4586 */
4587 if ((adv_dvc->tagqng_able & tidmask) &&
4588 sdev->tagged_supported) {
4589 unsigned short cfg_word;
4590 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
4591 cfg_word |= tidmask;
4592 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
4593 cfg_word);
4594 AdvWriteByteLram(iop_base,
4595 ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
4596 adv_dvc->max_dvc_qng);
4597 }
4598 }
4599
4600 if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
4601 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4602 adv_dvc->max_dvc_qng);
4603 } else {
4604 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4605 }
4606}
4607
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608/*
4609 * Set the number of commands to queue per device for the
4610 * specified host adapter.
4611 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004612static int advansys_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004614 asc_board_t *boardp = ASC_BOARDP(sdev->host);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004615 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004616
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004617 /*
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004618 * Save a pointer to the sdev and set its initial/maximum
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004619 * queue depth. Only save the pointer for a lun0 dev though.
4620 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004621 if (sdev->lun == 0)
4622 boardp->device[sdev->id] = sdev;
4623
4624 if (ASC_NARROW_BOARD(boardp))
4625 advansys_narrow_slave_configure(sdev,
4626 &boardp->dvc_var.asc_dvc_var);
4627 else
4628 advansys_wide_slave_configure(sdev,
4629 &boardp->dvc_var.adv_dvc_var);
4630
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004631 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632}
4633
4634/*
4635 * Complete all requests on the singly linked list pointed
4636 * to by 'scp'.
4637 *
4638 * Interrupts can be enabled on entry.
4639 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004640static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004642 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004644 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4645 while (scp != NULL) {
4646 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004648 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4649 tscp = REQPNEXT(scp);
4650 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004652 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004654 if (scp->use_sg)
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004655 dma_unmap_sg(boardp->dev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004656 (struct scatterlist *)scp->request_buffer,
4657 scp->use_sg, scp->sc_data_direction);
4658 else if (scp->request_bufflen)
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004659 dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004660 scp->request_bufflen,
4661 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004663 ASC_STATS(scp->device->host, done);
4664 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004666 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004668 scp = tscp;
4669 }
4670 ASC_DBG(2, "asc_scsi_done_list: done\n");
4671 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672}
4673
4674/*
4675 * Execute a single 'Scsi_Cmnd'.
4676 *
4677 * The function 'done' is called when the request has been completed.
4678 *
4679 * Scsi_Cmnd:
4680 *
4681 * host - board controlling device
4682 * device - device to send command
4683 * target - target of device
4684 * lun - lun of device
4685 * cmd_len - length of SCSI CDB
4686 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4687 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4688 *
4689 * if (use_sg == 0) {
4690 * request_buffer - buffer address for request
4691 * request_bufflen - length of request buffer
4692 * } else {
4693 * request_buffer - pointer to scatterlist structure
4694 * }
4695 *
4696 * sense_buffer - sense command buffer
4697 *
4698 * result (4 bytes of an int):
4699 * Byte Meaning
4700 * 0 SCSI Status Byte Code
4701 * 1 SCSI One Byte Message Code
4702 * 2 Host Error Code
4703 * 3 Mid-Level Error Code
4704 *
4705 * host driver fields:
4706 * SCp - Scsi_Pointer used for command processing status
4707 * scsi_done - used to save caller's done function
4708 * host_scribble - used for pointer to another struct scsi_cmnd
4709 *
4710 * If this function returns ASC_NOERROR the request has been enqueued
4711 * on the board's 'active' queue and will be completed from the
4712 * interrupt handler.
4713 *
4714 * If this function returns ASC_NOERROR the request has been enqueued
4715 * on the board's 'done' queue and must be completed by the caller.
4716 *
4717 * If ASC_BUSY is returned the request will be enqueued by the
4718 * caller on the target's waiting queue and re-tried later.
4719 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004720static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004722 asc_board_t *boardp;
4723 ASC_DVC_VAR *asc_dvc_varp;
4724 ADV_DVC_VAR *adv_dvc_varp;
4725 ADV_SCSI_REQ_Q *adv_scsiqp;
4726 struct scsi_device *device;
4727 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004729 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4730 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004732 boardp = ASC_BOARDP(scp->device->host);
4733 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004735 if (ASC_NARROW_BOARD(boardp)) {
4736 /*
4737 * Build and execute Narrow Board request.
4738 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004740 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004742 /*
4743 * Build Asc Library request structure using the
4744 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4745 *
4746 * If an error is returned, then the request has been
4747 * queued on the board done queue. It will be completed
4748 * by the caller.
4749 *
4750 * asc_build_req() can not return ASC_BUSY.
4751 */
4752 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4753 ASC_STATS(scp->device->host, build_error);
4754 return ASC_ERROR;
4755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004757 /*
4758 * Execute the command. If there is no error, add the command
4759 * to the active queue.
4760 */
4761 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4762 case ASC_NOERROR:
4763 ASC_STATS(scp->device->host, exe_noerror);
4764 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004765 * Increment monotonically increasing per device
4766 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004767 */
4768 boardp->reqcnt[scp->device->id]++;
4769 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004770 ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), "
4771 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004772 break;
4773 case ASC_BUSY:
4774 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004775 * Caller will enqueue request on the target's waiting
4776 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004777 */
4778 ASC_STATS(scp->device->host, exe_busy);
4779 break;
4780 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004781 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4782 "AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4783 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004784 ASC_STATS(scp->device->host, exe_error);
4785 scp->result = HOST_BYTE(DID_ERROR);
4786 asc_enqueue(&boardp->done, scp, ASC_BACK);
4787 break;
4788 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004789 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4790 "AscExeScsiQueue() unknown, err_code 0x%x\n",
4791 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004792 ASC_STATS(scp->device->host, exe_unknown);
4793 scp->result = HOST_BYTE(DID_ERROR);
4794 asc_enqueue(&boardp->done, scp, ASC_BACK);
4795 break;
4796 }
4797 } else {
4798 /*
4799 * Build and execute Wide Board request.
4800 */
4801 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004803 /*
4804 * Build and get a pointer to an Adv Library request structure.
4805 *
4806 * If the request is successfully built then send it below,
4807 * otherwise return with an error.
4808 */
4809 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4810 case ASC_NOERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004811 ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req "
4812 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004813 break;
4814 case ASC_BUSY:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004815 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4816 "ASC_BUSY\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004817 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004818 * If busy is returned the request has not been
4819 * enqueued. It will be enqueued by the caller on the
4820 * target's waiting queue and retried later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004821 *
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004822 * The asc_stats fields 'adv_build_noreq' and
4823 * 'adv_build_nosg' count wide board busy conditions.
4824 * They are updated in adv_build_req and
4825 * adv_get_sglist, respectively.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004826 */
4827 return ASC_BUSY;
4828 case ASC_ERROR:
4829 /*
4830 * If an error is returned, then the request has been
4831 * queued on the board done queue. It will be completed
4832 * by the caller.
4833 */
4834 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004835 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4836 "ASC_ERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004837 ASC_STATS(scp->device->host, build_error);
4838 return ASC_ERROR;
4839 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004841 /*
4842 * Execute the command. If there is no error, add the command
4843 * to the active queue.
4844 */
4845 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
4846 case ASC_NOERROR:
4847 ASC_STATS(scp->device->host, exe_noerror);
4848 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004849 * Increment monotonically increasing per device
4850 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004851 */
4852 boardp->reqcnt[scp->device->id]++;
4853 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004854 ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), "
4855 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004856 break;
4857 case ASC_BUSY:
4858 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004859 * Caller will enqueue request on the target's waiting
4860 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004861 */
4862 ASC_STATS(scp->device->host, exe_busy);
4863 break;
4864 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004865 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4866 "AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4867 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004868 ASC_STATS(scp->device->host, exe_error);
4869 scp->result = HOST_BYTE(DID_ERROR);
4870 asc_enqueue(&boardp->done, scp, ASC_BACK);
4871 break;
4872 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004873 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4874 "AdvExeScsiQueue() unknown, err_code 0x%x\n",
4875 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004876 ASC_STATS(scp->device->host, exe_unknown);
4877 scp->result = HOST_BYTE(DID_ERROR);
4878 asc_enqueue(&boardp->done, scp, ASC_BACK);
4879 break;
4880 }
4881 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004883 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
4884 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885}
4886
4887/*
4888 * Build a request structure for the Asc Library (Narrow Board).
4889 *
4890 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
4891 * used to build the request.
4892 *
4893 * If an error occurs, then queue the request on the board done
4894 * queue and return ASC_ERROR.
4895 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004896static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004898 /*
4899 * Mutually exclusive access is required to 'asc_scsi_q' and
4900 * 'asc_sg_head' until after the request is started.
4901 */
4902 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004904 /*
4905 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
4906 */
4907 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004909 /*
4910 * Build the ASC_SCSI_Q request.
4911 *
4912 * For narrow boards a CDB length maximum of 12 bytes
4913 * is supported.
4914 */
4915 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004916 ASC_PRINT3("asc_build_req: board %d: cmd_len %d > "
4917 "ASC_MAX_CDB_LEN %d\n", boardp->id, scp->cmd_len,
4918 ASC_MAX_CDB_LEN);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004919 scp->result = HOST_BYTE(DID_ERROR);
4920 asc_enqueue(&boardp->done, scp, ASC_BACK);
4921 return ASC_ERROR;
4922 }
4923 asc_scsi_q.cdbptr = &scp->cmnd[0];
4924 asc_scsi_q.q2.cdb_len = scp->cmd_len;
4925 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
4926 asc_scsi_q.q1.target_lun = scp->device->lun;
4927 asc_scsi_q.q2.target_ix =
4928 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
4929 asc_scsi_q.q1.sense_addr =
4930 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4931 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004933 /*
4934 * If there are any outstanding requests for the current target,
4935 * then every 255th request send an ORDERED request. This heuristic
4936 * tries to retain the benefit of request sorting while preventing
4937 * request starvation. 255 is the max number of tags or pending commands
4938 * a device may have outstanding.
4939 *
4940 * The request count is incremented below for every successfully
4941 * started request.
4942 *
4943 */
4944 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
4945 (boardp->reqcnt[scp->device->id] % 255) == 0) {
4946 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
4947 } else {
4948 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
4949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004951 /*
4952 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
4953 * buffer command.
4954 */
4955 if (scp->use_sg == 0) {
4956 /*
4957 * CDB request of single contiguous buffer.
4958 */
4959 ASC_STATS(scp->device->host, cont_cnt);
4960 scp->SCp.dma_handle = scp->request_bufflen ?
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004961 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004962 scp->request_bufflen,
4963 scp->sc_data_direction) : 0;
4964 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
4965 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
4966 ASC_STATS_ADD(scp->device->host, cont_xfer,
4967 ASC_CEILING(scp->request_bufflen, 512));
4968 asc_scsi_q.q1.sg_queue_cnt = 0;
4969 asc_scsi_q.sg_head = NULL;
4970 } else {
4971 /*
4972 * CDB scatter-gather request list.
4973 */
4974 int sgcnt;
4975 int use_sg;
4976 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004978 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004979 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
4980 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004982 if (use_sg > scp->device->host->sg_tablesize) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004983 ASC_PRINT3("asc_build_req: board %d: use_sg %d > "
4984 "sg_tablesize %d\n", boardp->id, use_sg,
4985 scp->device->host->sg_tablesize);
4986 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004987 scp->sc_data_direction);
4988 scp->result = HOST_BYTE(DID_ERROR);
4989 asc_enqueue(&boardp->done, scp, ASC_BACK);
4990 return ASC_ERROR;
4991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004993 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004995 /*
4996 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
4997 * structure to point to it.
4998 */
4999 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005001 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5002 asc_scsi_q.sg_head = &asc_sg_head;
5003 asc_scsi_q.q1.data_cnt = 0;
5004 asc_scsi_q.q1.data_addr = 0;
5005 /* This is a byte value, otherwise it would need to be swapped. */
5006 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5007 ASC_STATS_ADD(scp->device->host, sg_elem,
5008 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005010 /*
5011 * Convert scatter-gather list into ASC_SG_HEAD list.
5012 */
5013 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5014 asc_sg_head.sg_list[sgcnt].addr =
5015 cpu_to_le32(sg_dma_address(slp));
5016 asc_sg_head.sg_list[sgcnt].bytes =
5017 cpu_to_le32(sg_dma_len(slp));
5018 ASC_STATS_ADD(scp->device->host, sg_xfer,
5019 ASC_CEILING(sg_dma_len(slp), 512));
5020 }
5021 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005023 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5024 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005025
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005026 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027}
5028
5029/*
5030 * Build a request structure for the Adv Library (Wide Board).
5031 *
5032 * If an adv_req_t can not be allocated to issue the request,
5033 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5034 *
5035 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5036 * microcode for DMA addresses or math operations are byte swapped
5037 * to little-endian order.
5038 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005039static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005040adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005041 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005043 adv_req_t *reqp;
5044 ADV_SCSI_REQ_Q *scsiqp;
5045 int i;
5046 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005048 /*
5049 * Allocate an adv_req_t structure from the board to execute
5050 * the command.
5051 */
5052 if (boardp->adv_reqp == NULL) {
5053 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5054 ASC_STATS(scp->device->host, adv_build_noreq);
5055 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005057 reqp = boardp->adv_reqp;
5058 boardp->adv_reqp = reqp->next_reqp;
5059 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005062 /*
5063 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5064 */
5065 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005067 /*
5068 * Initialize the structure.
5069 */
5070 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005072 /*
5073 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5074 */
5075 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005077 /*
5078 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5079 */
5080 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005082 /*
5083 * Build the ADV_SCSI_REQ_Q request.
5084 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005086 /*
5087 * Set CDB length and copy it to the request structure.
5088 * For wide boards a CDB length maximum of 16 bytes
5089 * is supported.
5090 */
5091 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5092 ASC_PRINT3
5093 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5094 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5095 scp->result = HOST_BYTE(DID_ERROR);
5096 asc_enqueue(&boardp->done, scp, ASC_BACK);
5097 return ASC_ERROR;
5098 }
5099 scsiqp->cdb_len = scp->cmd_len;
5100 /* Copy first 12 CDB bytes to cdb[]. */
5101 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5102 scsiqp->cdb[i] = scp->cmnd[i];
5103 }
5104 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5105 for (; i < scp->cmd_len; i++) {
5106 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5107 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005109 scsiqp->target_id = scp->device->id;
5110 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005112 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5113 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005115 /*
5116 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5117 * buffer command.
5118 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005120 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5121 scsiqp->vdata_addr = scp->request_buffer;
5122 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5123
5124 if (scp->use_sg == 0) {
5125 /*
5126 * CDB request of single contiguous buffer.
5127 */
5128 reqp->sgblkp = NULL;
5129 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5130 if (scp->request_bufflen) {
5131 scsiqp->vdata_addr = scp->request_buffer;
5132 scp->SCp.dma_handle =
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005133 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005134 scp->request_bufflen,
5135 scp->sc_data_direction);
5136 } else {
5137 scsiqp->vdata_addr = NULL;
5138 scp->SCp.dma_handle = 0;
5139 }
5140 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5141 scsiqp->sg_list_ptr = NULL;
5142 scsiqp->sg_real_addr = 0;
5143 ASC_STATS(scp->device->host, cont_cnt);
5144 ASC_STATS_ADD(scp->device->host, cont_xfer,
5145 ASC_CEILING(scp->request_bufflen, 512));
5146 } else {
5147 /*
5148 * CDB scatter-gather request list.
5149 */
5150 struct scatterlist *slp;
5151 int use_sg;
5152
5153 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005154 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
5155 scp->sc_data_direction);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005156
5157 if (use_sg > ADV_MAX_SG_LIST) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005158 ASC_PRINT3("adv_build_req: board %d: use_sg %d > "
5159 "ADV_MAX_SG_LIST %d\n", boardp->id, use_sg,
5160 scp->device->host->sg_tablesize);
5161 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005162 scp->sc_data_direction);
5163 scp->result = HOST_BYTE(DID_ERROR);
5164 asc_enqueue(&boardp->done, scp, ASC_BACK);
5165
5166 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005167 * Free the 'adv_req_t' structure by adding it back
5168 * to the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005169 */
5170 reqp->next_reqp = boardp->adv_reqp;
5171 boardp->adv_reqp = reqp;
5172
5173 return ASC_ERROR;
5174 }
5175
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005176 ret = adv_get_sglist(boardp, reqp, scp, use_sg);
5177 if (ret != ADV_SUCCESS) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005178 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005179 * Free the adv_req_t structure by adding it back to
5180 * the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005181 */
5182 reqp->next_reqp = boardp->adv_reqp;
5183 boardp->adv_reqp = reqp;
5184
5185 return ret;
5186 }
5187
5188 ASC_STATS(scp->device->host, sg_cnt);
5189 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5190 }
5191
5192 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5193 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5194
5195 *adv_scsiqpp = scsiqp;
5196
5197 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198}
5199
5200/*
5201 * Build scatter-gather list for Adv Library (Wide Board).
5202 *
5203 * Additional ADV_SG_BLOCK structures will need to be allocated
5204 * if the total number of scatter-gather elements exceeds
5205 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5206 * assumed to be physically contiguous.
5207 *
5208 * Return:
5209 * ADV_SUCCESS(1) - SG List successfully created
5210 * ADV_ERROR(-1) - SG List creation failed
5211 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005212static int
5213adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5214 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005216 adv_sgblk_t *sgblkp;
5217 ADV_SCSI_REQ_Q *scsiqp;
5218 struct scatterlist *slp;
5219 int sg_elem_cnt;
5220 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5221 ADV_PADDR sg_block_paddr;
5222 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005224 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5225 slp = (struct scatterlist *)scp->request_buffer;
5226 sg_elem_cnt = use_sg;
5227 prev_sg_block = NULL;
5228 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005230 do {
5231 /*
5232 * Allocate a 'adv_sgblk_t' structure from the board free
5233 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5234 * (15) scatter-gather elements.
5235 */
5236 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5237 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5238 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005240 /*
5241 * Allocation failed. Free 'adv_sgblk_t' structures already
5242 * allocated for the request.
5243 */
5244 while ((sgblkp = reqp->sgblkp) != NULL) {
5245 /* Remove 'sgblkp' from the request list. */
5246 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005248 /* Add 'sgblkp' to the board free list. */
5249 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5250 boardp->adv_sgblkp = sgblkp;
5251 }
5252 return ASC_BUSY;
5253 } else {
5254 /* Complete 'adv_sgblk_t' board allocation. */
5255 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5256 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005258 /*
5259 * Get 8 byte aligned virtual and physical addresses for
5260 * the allocated ADV_SG_BLOCK structure.
5261 */
5262 sg_block =
5263 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5264 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005266 /*
5267 * Check if this is the first 'adv_sgblk_t' for the request.
5268 */
5269 if (reqp->sgblkp == NULL) {
5270 /* Request's first scatter-gather block. */
5271 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005273 /*
5274 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5275 * address pointers.
5276 */
5277 scsiqp->sg_list_ptr = sg_block;
5278 scsiqp->sg_real_addr =
5279 cpu_to_le32(sg_block_paddr);
5280 } else {
5281 /* Request's second or later scatter-gather block. */
5282 sgblkp->next_sgblkp = reqp->sgblkp;
5283 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005285 /*
5286 * Point the previous ADV_SG_BLOCK structure to
5287 * the newly allocated ADV_SG_BLOCK structure.
5288 */
5289 ASC_ASSERT(prev_sg_block != NULL);
5290 prev_sg_block->sg_ptr =
5291 cpu_to_le32(sg_block_paddr);
5292 }
5293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005295 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5296 sg_block->sg_list[i].sg_addr =
5297 cpu_to_le32(sg_dma_address(slp));
5298 sg_block->sg_list[i].sg_count =
5299 cpu_to_le32(sg_dma_len(slp));
5300 ASC_STATS_ADD(scp->device->host, sg_xfer,
5301 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005303 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5304 sg_block->sg_cnt = i + 1;
5305 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5306 return ADV_SUCCESS;
5307 }
5308 slp++;
5309 }
5310 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5311 prev_sg_block = sg_block;
5312 }
5313 while (1);
5314 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315}
5316
5317/*
5318 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5319 *
5320 * Interrupt callback function for the Narrow SCSI Asc Library.
5321 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005322static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005324 asc_board_t *boardp;
5325 struct scsi_cmnd *scp;
5326 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005328 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5329 (ulong)asc_dvc_varp, (ulong)qdonep);
5330 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005332 /*
5333 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5334 * command that has been completed.
5335 */
5336 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5337 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005339 if (scp == NULL) {
5340 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5341 return;
5342 }
5343 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005345 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005346 ASC_STATS(shost, callback);
5347 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005349 /*
5350 * If the request isn't found on the active queue, it may
5351 * have been removed to handle a reset request.
5352 * Display a message and return.
5353 */
5354 boardp = ASC_BOARDP(shost);
5355 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5356 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5357 ASC_PRINT2
5358 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5359 boardp->id, (ulong)scp);
5360 return;
5361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005363 /*
5364 * 'qdonep' contains the command's ending status.
5365 */
5366 switch (qdonep->d3.done_stat) {
5367 case QD_NO_ERROR:
5368 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5369 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005371 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005372 * Check for an underrun condition.
5373 *
5374 * If there was no error and an underrun condition, then
Matthew Wilcox47d853c2007-07-26 11:41:33 -04005375 * return the number of underrun bytes.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005376 */
5377 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5378 qdonep->remain_bytes <= scp->request_bufflen) {
5379 ASC_DBG1(1,
5380 "asc_isr_callback: underrun condition %u bytes\n",
5381 (unsigned)qdonep->remain_bytes);
5382 scp->resid = qdonep->remain_bytes;
5383 }
5384 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005386 case QD_WITH_ERROR:
5387 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5388 switch (qdonep->d3.host_stat) {
5389 case QHSTA_NO_ERROR:
5390 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5391 ASC_DBG(2,
5392 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5393 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5394 sizeof(scp->sense_buffer));
5395 /*
5396 * Note: The 'status_byte()' macro used by target drivers
5397 * defined in scsi.h shifts the status byte returned by
5398 * host drivers right by 1 bit. This is why target drivers
5399 * also use right shifted status byte definitions. For
5400 * instance target drivers use CHECK_CONDITION, defined to
5401 * 0x1, instead of the SCSI defined check condition value
5402 * of 0x2. Host drivers are supposed to return the status
5403 * byte as it is defined by SCSI.
5404 */
5405 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5406 STATUS_BYTE(qdonep->d3.scsi_stat);
5407 } else {
5408 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5409 }
5410 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005412 default:
5413 /* QHSTA error occurred */
5414 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5415 qdonep->d3.host_stat);
5416 scp->result = HOST_BYTE(DID_BAD_TARGET);
5417 break;
5418 }
5419 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005421 case QD_ABORTED_BY_HOST:
5422 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5423 scp->result =
5424 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5425 scsi_msg) |
5426 STATUS_BYTE(qdonep->d3.scsi_stat);
5427 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005429 default:
5430 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5431 qdonep->d3.done_stat);
5432 scp->result =
5433 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5434 scsi_msg) |
5435 STATUS_BYTE(qdonep->d3.scsi_stat);
5436 break;
5437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005439 /*
5440 * If the 'init_tidmask' bit isn't already set for the target and the
5441 * current request finished normally, then set the bit for the target
5442 * to indicate that a device is present.
5443 */
5444 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5445 qdonep->d3.done_stat == QD_NO_ERROR &&
5446 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5447 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005450 /*
5451 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5452 * function, add the command to the end of the board's done queue.
5453 * The done function for the command will be called from
5454 * advansys_interrupt().
5455 */
5456 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005458 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459}
5460
5461/*
5462 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5463 *
5464 * Callback function for the Wide SCSI Adv Library.
5465 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005466static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005468 asc_board_t *boardp;
5469 adv_req_t *reqp;
5470 adv_sgblk_t *sgblkp;
5471 struct scsi_cmnd *scp;
5472 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005473 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005475 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5476 (ulong)adv_dvc_varp, (ulong)scsiqp);
5477 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005479 /*
5480 * Get the adv_req_t structure for the command that has been
5481 * completed. The adv_req_t structure actually contains the
5482 * completed ADV_SCSI_REQ_Q structure.
5483 */
5484 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5485 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5486 if (reqp == NULL) {
5487 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5488 return;
5489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005491 /*
5492 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5493 * command that has been completed.
5494 *
5495 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5496 * if any, are dropped, because a board structure pointer can not be
5497 * determined.
5498 */
5499 scp = reqp->cmndp;
5500 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5501 if (scp == NULL) {
5502 ASC_PRINT
5503 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5504 return;
5505 }
5506 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005508 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005509 ASC_STATS(shost, callback);
5510 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005512 /*
5513 * If the request isn't found on the active queue, it may have been
5514 * removed to handle a reset request. Display a message and return.
5515 *
5516 * Note: Because the structure may still be in use don't attempt
5517 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5518 */
5519 boardp = ASC_BOARDP(shost);
5520 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5521 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5522 ASC_PRINT2
5523 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5524 boardp->id, (ulong)scp);
5525 return;
5526 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005528 /*
5529 * 'done_status' contains the command's ending status.
5530 */
5531 switch (scsiqp->done_status) {
5532 case QD_NO_ERROR:
5533 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5534 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005536 /*
5537 * Check for an underrun condition.
5538 *
5539 * If there was no error and an underrun condition, then
5540 * then return the number of underrun bytes.
5541 */
5542 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5543 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5544 resid_cnt <= scp->request_bufflen) {
5545 ASC_DBG1(1,
5546 "adv_isr_callback: underrun condition %lu bytes\n",
5547 (ulong)resid_cnt);
5548 scp->resid = resid_cnt;
5549 }
5550 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005552 case QD_WITH_ERROR:
5553 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5554 switch (scsiqp->host_status) {
5555 case QHSTA_NO_ERROR:
5556 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5557 ASC_DBG(2,
5558 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5559 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5560 sizeof(scp->sense_buffer));
5561 /*
5562 * Note: The 'status_byte()' macro used by target drivers
5563 * defined in scsi.h shifts the status byte returned by
5564 * host drivers right by 1 bit. This is why target drivers
5565 * also use right shifted status byte definitions. For
5566 * instance target drivers use CHECK_CONDITION, defined to
5567 * 0x1, instead of the SCSI defined check condition value
5568 * of 0x2. Host drivers are supposed to return the status
5569 * byte as it is defined by SCSI.
5570 */
5571 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5572 STATUS_BYTE(scsiqp->scsi_status);
5573 } else {
5574 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5575 }
5576 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005578 default:
5579 /* Some other QHSTA error occurred. */
5580 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5581 scsiqp->host_status);
5582 scp->result = HOST_BYTE(DID_BAD_TARGET);
5583 break;
5584 }
5585 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005587 case QD_ABORTED_BY_HOST:
5588 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5589 scp->result =
5590 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5591 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005593 default:
5594 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5595 scsiqp->done_status);
5596 scp->result =
5597 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5598 break;
5599 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005601 /*
5602 * If the 'init_tidmask' bit isn't already set for the target and the
5603 * current request finished normally, then set the bit for the target
5604 * to indicate that a device is present.
5605 */
5606 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5607 scsiqp->done_status == QD_NO_ERROR &&
5608 scsiqp->host_status == QHSTA_NO_ERROR) {
5609 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005612 /*
5613 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5614 * function, add the command to the end of the board's done queue.
5615 * The done function for the command will be called from
5616 * advansys_interrupt().
5617 */
5618 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005620 /*
5621 * Free all 'adv_sgblk_t' structures allocated for the request.
5622 */
5623 while ((sgblkp = reqp->sgblkp) != NULL) {
5624 /* Remove 'sgblkp' from the request list. */
5625 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005627 /* Add 'sgblkp' to the board free list. */
5628 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5629 boardp->adv_sgblkp = sgblkp;
5630 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005632 /*
5633 * Free the adv_req_t structure used with the command by adding
5634 * it back to the board free list.
5635 */
5636 reqp->next_reqp = boardp->adv_reqp;
5637 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005639 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005641 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642}
5643
5644/*
5645 * adv_async_callback() - Adv Library asynchronous event callback function.
5646 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005647static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005649 switch (code) {
5650 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5651 /*
5652 * The firmware detected a SCSI Bus reset.
5653 */
5654 ASC_DBG(0,
5655 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5656 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005658 case ADV_ASYNC_RDMA_FAILURE:
5659 /*
5660 * Handle RDMA failure by resetting the SCSI Bus and
5661 * possibly the chip if it is unresponsive. Log the error
5662 * with a unique code.
5663 */
5664 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5665 AdvResetChipAndSB(adv_dvc_varp);
5666 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005668 case ADV_HOST_SCSI_BUS_RESET:
5669 /*
5670 * Host generated SCSI bus reset occurred.
5671 */
5672 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5673 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005675 default:
5676 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5677 break;
5678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679}
5680
5681/*
5682 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5683 * to indicate a command is queued for the device.
5684 *
5685 * 'flag' may be either ASC_FRONT or ASC_BACK.
5686 *
5687 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5688 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005689static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005691 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005693 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5694 (ulong)ascq, (ulong)reqp, flag);
5695 ASC_ASSERT(reqp != NULL);
5696 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5697 tid = REQPTID(reqp);
5698 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5699 if (flag == ASC_FRONT) {
5700 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5701 ascq->q_first[tid] = reqp;
5702 /* If the queue was empty, set the last pointer. */
5703 if (ascq->q_last[tid] == NULL) {
5704 ascq->q_last[tid] = reqp;
5705 }
5706 } else { /* ASC_BACK */
5707 if (ascq->q_last[tid] != NULL) {
5708 ascq->q_last[tid]->host_scribble =
5709 (unsigned char *)reqp;
5710 }
5711 ascq->q_last[tid] = reqp;
5712 reqp->host_scribble = NULL;
5713 /* If the queue was empty, set the first pointer. */
5714 if (ascq->q_first[tid] == NULL) {
5715 ascq->q_first[tid] = reqp;
5716 }
5717 }
5718 /* The queue has at least one entry, set its bit. */
5719 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005721 /* Maintain request queue statistics. */
5722 ascq->q_tot_cnt[tid]++;
5723 ascq->q_cur_cnt[tid]++;
5724 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5725 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5726 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5727 tid, ascq->q_max_cnt[tid]);
5728 }
5729 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005731 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5732 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733}
5734
5735/*
5736 * Return first queued 'REQP' on the specified queue for
5737 * the specified target device. Clear the 'tidmask' bit for
5738 * the device if no more commands are left queued for it.
5739 *
5740 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5741 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005742static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005744 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005746 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5747 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5748 if ((reqp = ascq->q_first[tid]) != NULL) {
5749 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5750 ascq->q_first[tid] = REQPNEXT(reqp);
5751 /* If the queue is empty, clear its bit and the last pointer. */
5752 if (ascq->q_first[tid] == NULL) {
5753 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5754 ASC_ASSERT(ascq->q_last[tid] == reqp);
5755 ascq->q_last[tid] = NULL;
5756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005758 /* Maintain request queue statistics. */
5759 ascq->q_cur_cnt[tid]--;
5760 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
5761 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005763 }
5764 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
5765 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766}
5767
5768/*
5769 * Return a pointer to a singly linked list of all the requests queued
5770 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
5771 *
5772 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
5773 * the last request returned in the singly linked list.
5774 *
5775 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
5776 * then all queued requests are concatenated into one list and
5777 * returned.
5778 *
5779 * Note: If 'lastpp' is used to append a new list to the end of
5780 * an old list, only change the old list last pointer if '*lastpp'
5781 * (or the function return value) is not NULL, i.e. use a temporary
5782 * variable for 'lastpp' and check its value after the function return
5783 * before assigning it to the list last pointer.
5784 *
5785 * Unfortunately collecting queuing time statistics adds overhead to
5786 * the function that isn't inherent to the function's algorithm.
5787 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005788static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005790 REQP firstp, lastp;
5791 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005793 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5794 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005796 /*
5797 * If 'tid' is not ASC_TID_ALL, return requests only for
5798 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
5799 * requests for all tids.
5800 */
5801 if (tid != ASC_TID_ALL) {
5802 /* Return all requests for the specified 'tid'. */
5803 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
5804 /* List is empty; Set first and last return pointers to NULL. */
5805 firstp = lastp = NULL;
5806 } else {
5807 firstp = ascq->q_first[tid];
5808 lastp = ascq->q_last[tid];
5809 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
5810 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005812 {
5813 REQP reqp;
5814 ascq->q_cur_cnt[tid] = 0;
5815 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5816 REQTIMESTAT("asc_dequeue_list", ascq,
5817 reqp, tid);
5818 }
5819 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005821 }
5822 } else {
5823 /* Return all requests for all tids. */
5824 firstp = lastp = NULL;
5825 for (i = 0; i <= ADV_MAX_TID; i++) {
5826 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
5827 if (firstp == NULL) {
5828 firstp = ascq->q_first[i];
5829 lastp = ascq->q_last[i];
5830 } else {
5831 ASC_ASSERT(lastp != NULL);
5832 lastp->host_scribble =
5833 (unsigned char *)ascq->q_first[i];
5834 lastp = ascq->q_last[i];
5835 }
5836 ascq->q_first[i] = ascq->q_last[i] = NULL;
5837 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005839 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005841 }
5842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005844 {
5845 REQP reqp;
5846 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5847 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
5848 reqp->device->id);
5849 }
5850 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005852 }
5853 if (lastpp) {
5854 *lastpp = lastp;
5855 }
5856 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
5857 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858}
5859
5860/*
5861 * Remove the specified 'REQP' from the specified queue for
5862 * the specified target device. Clear the 'tidmask' bit for the
5863 * device if no more commands are left queued for it.
5864 *
5865 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
5866 *
5867 * Return ASC_TRUE if the command was found and removed,
5868 * otherwise return ASC_FALSE.
5869 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005870static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005872 REQP currp, prevp;
5873 int tid;
5874 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005876 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
5877 (ulong)ascq, (ulong)reqp);
5878 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005880 tid = REQPTID(reqp);
5881 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005883 /*
5884 * Handle the common case of 'reqp' being the first
5885 * entry on the queue.
5886 */
5887 if (reqp == ascq->q_first[tid]) {
5888 ret = ASC_TRUE;
5889 ascq->q_first[tid] = REQPNEXT(reqp);
5890 /* If the queue is now empty, clear its bit and the last pointer. */
5891 if (ascq->q_first[tid] == NULL) {
5892 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5893 ASC_ASSERT(ascq->q_last[tid] == reqp);
5894 ascq->q_last[tid] = NULL;
5895 }
5896 } else if (ascq->q_first[tid] != NULL) {
5897 ASC_ASSERT(ascq->q_last[tid] != NULL);
5898 /*
5899 * Because the case of 'reqp' being the first entry has been
5900 * handled above and it is known the queue is not empty, if
5901 * 'reqp' is found on the queue it is guaranteed the queue will
5902 * not become empty and that 'q_first[tid]' will not be changed.
5903 *
5904 * Set 'prevp' to the first entry, 'currp' to the second entry,
5905 * and search for 'reqp'.
5906 */
5907 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
5908 currp; prevp = currp, currp = REQPNEXT(currp)) {
5909 if (currp == reqp) {
5910 ret = ASC_TRUE;
5911 prevp->host_scribble =
5912 (unsigned char *)REQPNEXT(currp);
5913 reqp->host_scribble = NULL;
5914 if (ascq->q_last[tid] == reqp) {
5915 ascq->q_last[tid] = prevp;
5916 }
5917 break;
5918 }
5919 }
5920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005922 /* Maintain request queue statistics. */
5923 if (ret == ASC_TRUE) {
5924 ascq->q_cur_cnt[tid]--;
5925 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
5926 }
5927 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005929 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
5930 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931}
5932
5933/*
5934 * Execute as many queued requests as possible for the specified queue.
5935 *
5936 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
5937 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005938static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005940 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
5941 REQP reqp;
5942 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005944 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
5945 /*
5946 * Execute queued commands for devices attached to
5947 * the current board in round-robin fashion.
5948 */
5949 scan_tidmask = ascq->q_tidmask;
5950 do {
5951 for (i = 0; i <= ADV_MAX_TID; i++) {
5952 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
5953 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
5954 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
5955 } else
5956 if (asc_execute_scsi_cmnd
5957 ((struct scsi_cmnd *)reqp)
5958 == ASC_BUSY) {
5959 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
5960 /*
5961 * The request returned ASC_BUSY. Enqueue at the front of
5962 * target's waiting list to maintain correct ordering.
5963 */
5964 asc_enqueue(ascq, reqp, ASC_FRONT);
5965 }
5966 }
5967 }
5968 } while (scan_tidmask);
5969 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970}
5971
5972#ifdef CONFIG_PROC_FS
5973/*
5974 * asc_prt_board_devices()
5975 *
5976 * Print driver information for devices attached to the board.
5977 *
5978 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5979 * cf. asc_prt_line().
5980 *
5981 * Return the number of characters copied into 'cp'. No more than
5982 * 'cplen' characters will be copied to 'cp'.
5983 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005984static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005986 asc_board_t *boardp;
5987 int leftlen;
5988 int totlen;
5989 int len;
5990 int chip_scsi_id;
5991 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005993 boardp = ASC_BOARDP(shost);
5994 leftlen = cplen;
5995 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005997 len = asc_prt_line(cp, leftlen,
5998 "\nDevice Information for AdvanSys SCSI Host %d:\n",
5999 shost->host_no);
6000 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006001
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006002 if (ASC_NARROW_BOARD(boardp)) {
6003 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6004 } else {
6005 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006008 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6009 ASC_PRT_NEXT();
6010 for (i = 0; i <= ADV_MAX_TID; i++) {
6011 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6012 len = asc_prt_line(cp, leftlen, " %X,", i);
6013 ASC_PRT_NEXT();
6014 }
6015 }
6016 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6017 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006019 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020}
6021
6022/*
6023 * Display Wide Board BIOS Information.
6024 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006025static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006026{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006027 asc_board_t *boardp;
6028 int leftlen;
6029 int totlen;
6030 int len;
6031 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006033 boardp = ASC_BOARDP(shost);
6034 leftlen = cplen;
6035 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006037 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6038 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006040 /*
6041 * If the BIOS saved a valid signature, then fill in
6042 * the BIOS code segment base address.
6043 */
6044 if (boardp->bios_signature != 0x55AA) {
6045 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6046 ASC_PRT_NEXT();
6047 len = asc_prt_line(cp, leftlen,
6048 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6049 ASC_PRT_NEXT();
6050 len = asc_prt_line(cp, leftlen,
6051 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6052 ASC_PRT_NEXT();
6053 } else {
6054 major = (boardp->bios_version >> 12) & 0xF;
6055 minor = (boardp->bios_version >> 8) & 0xF;
6056 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006058 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6059 major, minor,
6060 letter >= 26 ? '?' : letter + 'A');
6061 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006062
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006063 /*
6064 * Current available ROM BIOS release is 3.1I for UW
6065 * and 3.2I for U2W. This code doesn't differentiate
6066 * UW and U2W boards.
6067 */
6068 if (major < 3 || (major <= 3 && minor < 1) ||
6069 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6070 len = asc_prt_line(cp, leftlen,
6071 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6072 ASC_PRT_NEXT();
6073 len = asc_prt_line(cp, leftlen,
6074 "ftp://ftp.connectcom.net/pub\n");
6075 ASC_PRT_NEXT();
6076 }
6077 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006079 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080}
6081
6082/*
6083 * Add serial number to information bar if signature AAh
6084 * is found in at bit 15-9 (7 bits) of word 1.
6085 *
6086 * Serial Number consists fo 12 alpha-numeric digits.
6087 *
6088 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6089 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6090 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6091 * 5 - Product revision (A-J) Word0: " "
6092 *
6093 * Signature Word1: 15-9 (7 bits)
6094 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6095 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6096 *
6097 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6098 *
6099 * Note 1: Only production cards will have a serial number.
6100 *
6101 * Note 2: Signature is most significant 7 bits (0xFE).
6102 *
6103 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6104 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006105static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006107 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006109 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6110 return ASC_FALSE;
6111 } else {
6112 /*
6113 * First word - 6 digits.
6114 */
6115 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006117 /* Product type - 1st digit. */
6118 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6119 /* Product type is P=Prototype */
6120 *cp += 0x8;
6121 }
6122 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006124 /* Manufacturing location - 2nd digit. */
6125 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006126
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006127 /* Product ID - 3rd, 4th digits. */
6128 num = w & 0x3FF;
6129 *cp++ = '0' + (num / 100);
6130 num %= 100;
6131 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006133 /* Product revision - 5th digit. */
6134 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006136 /*
6137 * Second word
6138 */
6139 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006140
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006141 /*
6142 * Year - 6th digit.
6143 *
6144 * If bit 15 of third word is set, then the
6145 * last digit of the year is greater than 7.
6146 */
6147 if (serialnum[2] & 0x8000) {
6148 *cp++ = '8' + ((w & 0x1C0) >> 6);
6149 } else {
6150 *cp++ = '0' + ((w & 0x1C0) >> 6);
6151 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006152
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006153 /* Week of year - 7th, 8th digits. */
6154 num = w & 0x003F;
6155 *cp++ = '0' + num / 10;
6156 num %= 10;
6157 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006158
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006159 /*
6160 * Third word
6161 */
6162 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006164 /* Serial number - 9th digit. */
6165 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006167 /* 10th, 11th, 12th digits. */
6168 num = w % 1000;
6169 *cp++ = '0' + num / 100;
6170 num %= 100;
6171 *cp++ = '0' + num / 10;
6172 num %= 10;
6173 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006174
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006175 *cp = '\0'; /* Null Terminate the string. */
6176 return ASC_TRUE;
6177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178}
6179
6180/*
6181 * asc_prt_asc_board_eeprom()
6182 *
6183 * Print board EEPROM configuration.
6184 *
6185 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6186 * cf. asc_prt_line().
6187 *
6188 * Return the number of characters copied into 'cp'. No more than
6189 * 'cplen' characters will be copied to 'cp'.
6190 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006191static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006192{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006193 asc_board_t *boardp;
6194 ASC_DVC_VAR *asc_dvc_varp;
6195 int leftlen;
6196 int totlen;
6197 int len;
6198 ASCEEP_CONFIG *ep;
6199 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006201 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006202#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006203 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006205 boardp = ASC_BOARDP(shost);
6206 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6207 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006209 leftlen = cplen;
6210 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006212 len = asc_prt_line(cp, leftlen,
6213 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6214 shost->host_no);
6215 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006216
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006217 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6218 == ASC_TRUE) {
6219 len =
6220 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6221 serialstr);
6222 ASC_PRT_NEXT();
6223 } else {
6224 if (ep->adapter_info[5] == 0xBB) {
6225 len = asc_prt_line(cp, leftlen,
6226 " Default Settings Used for EEPROM-less Adapter.\n");
6227 ASC_PRT_NEXT();
6228 } else {
6229 len = asc_prt_line(cp, leftlen,
6230 " Serial Number Signature Not Present.\n");
6231 ASC_PRT_NEXT();
6232 }
6233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006235 len = asc_prt_line(cp, leftlen,
6236 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6237 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6238 ep->max_tag_qng);
6239 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006241 len = asc_prt_line(cp, leftlen,
6242 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6243 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006245 len = asc_prt_line(cp, leftlen, " Target ID: ");
6246 ASC_PRT_NEXT();
6247 for (i = 0; i <= ASC_MAX_TID; i++) {
6248 len = asc_prt_line(cp, leftlen, " %d", i);
6249 ASC_PRT_NEXT();
6250 }
6251 len = asc_prt_line(cp, leftlen, "\n");
6252 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006254 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6255 ASC_PRT_NEXT();
6256 for (i = 0; i <= ASC_MAX_TID; i++) {
6257 len = asc_prt_line(cp, leftlen, " %c",
6258 (ep->
6259 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6260 'N');
6261 ASC_PRT_NEXT();
6262 }
6263 len = asc_prt_line(cp, leftlen, "\n");
6264 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006266 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6267 ASC_PRT_NEXT();
6268 for (i = 0; i <= ASC_MAX_TID; i++) {
6269 len = asc_prt_line(cp, leftlen, " %c",
6270 (ep->
6271 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6272 'N');
6273 ASC_PRT_NEXT();
6274 }
6275 len = asc_prt_line(cp, leftlen, "\n");
6276 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006278 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6279 ASC_PRT_NEXT();
6280 for (i = 0; i <= ASC_MAX_TID; i++) {
6281 len = asc_prt_line(cp, leftlen, " %c",
6282 (ep->
6283 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6284 'N');
6285 ASC_PRT_NEXT();
6286 }
6287 len = asc_prt_line(cp, leftlen, "\n");
6288 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006290 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6291 ASC_PRT_NEXT();
6292 for (i = 0; i <= ASC_MAX_TID; i++) {
6293 len = asc_prt_line(cp, leftlen, " %c",
6294 (ep->
6295 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6296 'N');
6297 ASC_PRT_NEXT();
6298 }
6299 len = asc_prt_line(cp, leftlen, "\n");
6300 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301
6302#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006303 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6304 len = asc_prt_line(cp, leftlen,
6305 " Host ISA DMA speed: %d MB/S\n",
6306 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6307 ASC_PRT_NEXT();
6308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006309#endif /* CONFIG_ISA */
6310
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006311 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312}
6313
6314/*
6315 * asc_prt_adv_board_eeprom()
6316 *
6317 * Print board EEPROM configuration.
6318 *
6319 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6320 * cf. asc_prt_line().
6321 *
6322 * Return the number of characters copied into 'cp'. No more than
6323 * 'cplen' characters will be copied to 'cp'.
6324 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006325static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006327 asc_board_t *boardp;
6328 ADV_DVC_VAR *adv_dvc_varp;
6329 int leftlen;
6330 int totlen;
6331 int len;
6332 int i;
6333 char *termstr;
6334 uchar serialstr[13];
6335 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6336 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6337 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6338 ushort word;
6339 ushort *wordp;
6340 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006342 boardp = ASC_BOARDP(shost);
6343 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6344 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6345 ep_3550 = &boardp->eep_config.adv_3550_eep;
6346 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6347 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6348 } else {
6349 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006352 leftlen = cplen;
6353 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006354
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006355 len = asc_prt_line(cp, leftlen,
6356 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6357 shost->host_no);
6358 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006360 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6361 wordp = &ep_3550->serial_number_word1;
6362 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6363 wordp = &ep_38C0800->serial_number_word1;
6364 } else {
6365 wordp = &ep_38C1600->serial_number_word1;
6366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006368 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6369 len =
6370 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6371 serialstr);
6372 ASC_PRT_NEXT();
6373 } else {
6374 len = asc_prt_line(cp, leftlen,
6375 " Serial Number Signature Not Present.\n");
6376 ASC_PRT_NEXT();
6377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006378
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006379 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6380 len = asc_prt_line(cp, leftlen,
6381 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6382 ep_3550->adapter_scsi_id,
6383 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6384 ASC_PRT_NEXT();
6385 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6386 len = asc_prt_line(cp, leftlen,
6387 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6388 ep_38C0800->adapter_scsi_id,
6389 ep_38C0800->max_host_qng,
6390 ep_38C0800->max_dvc_qng);
6391 ASC_PRT_NEXT();
6392 } else {
6393 len = asc_prt_line(cp, leftlen,
6394 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6395 ep_38C1600->adapter_scsi_id,
6396 ep_38C1600->max_host_qng,
6397 ep_38C1600->max_dvc_qng);
6398 ASC_PRT_NEXT();
6399 }
6400 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6401 word = ep_3550->termination;
6402 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6403 word = ep_38C0800->termination_lvd;
6404 } else {
6405 word = ep_38C1600->termination_lvd;
6406 }
6407 switch (word) {
6408 case 1:
6409 termstr = "Low Off/High Off";
6410 break;
6411 case 2:
6412 termstr = "Low Off/High On";
6413 break;
6414 case 3:
6415 termstr = "Low On/High On";
6416 break;
6417 default:
6418 case 0:
6419 termstr = "Automatic";
6420 break;
6421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006422
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006423 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6424 len = asc_prt_line(cp, leftlen,
6425 " termination: %u (%s), bios_ctrl: 0x%x\n",
6426 ep_3550->termination, termstr,
6427 ep_3550->bios_ctrl);
6428 ASC_PRT_NEXT();
6429 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6430 len = asc_prt_line(cp, leftlen,
6431 " termination: %u (%s), bios_ctrl: 0x%x\n",
6432 ep_38C0800->termination_lvd, termstr,
6433 ep_38C0800->bios_ctrl);
6434 ASC_PRT_NEXT();
6435 } else {
6436 len = asc_prt_line(cp, leftlen,
6437 " termination: %u (%s), bios_ctrl: 0x%x\n",
6438 ep_38C1600->termination_lvd, termstr,
6439 ep_38C1600->bios_ctrl);
6440 ASC_PRT_NEXT();
6441 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006443 len = asc_prt_line(cp, leftlen, " Target ID: ");
6444 ASC_PRT_NEXT();
6445 for (i = 0; i <= ADV_MAX_TID; i++) {
6446 len = asc_prt_line(cp, leftlen, " %X", i);
6447 ASC_PRT_NEXT();
6448 }
6449 len = asc_prt_line(cp, leftlen, "\n");
6450 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006451
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006452 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6453 word = ep_3550->disc_enable;
6454 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6455 word = ep_38C0800->disc_enable;
6456 } else {
6457 word = ep_38C1600->disc_enable;
6458 }
6459 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6460 ASC_PRT_NEXT();
6461 for (i = 0; i <= ADV_MAX_TID; i++) {
6462 len = asc_prt_line(cp, leftlen, " %c",
6463 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6464 ASC_PRT_NEXT();
6465 }
6466 len = asc_prt_line(cp, leftlen, "\n");
6467 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006469 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6470 word = ep_3550->tagqng_able;
6471 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6472 word = ep_38C0800->tagqng_able;
6473 } else {
6474 word = ep_38C1600->tagqng_able;
6475 }
6476 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6477 ASC_PRT_NEXT();
6478 for (i = 0; i <= ADV_MAX_TID; i++) {
6479 len = asc_prt_line(cp, leftlen, " %c",
6480 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6481 ASC_PRT_NEXT();
6482 }
6483 len = asc_prt_line(cp, leftlen, "\n");
6484 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006485
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006486 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6487 word = ep_3550->start_motor;
6488 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6489 word = ep_38C0800->start_motor;
6490 } else {
6491 word = ep_38C1600->start_motor;
6492 }
6493 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6494 ASC_PRT_NEXT();
6495 for (i = 0; i <= ADV_MAX_TID; i++) {
6496 len = asc_prt_line(cp, leftlen, " %c",
6497 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6498 ASC_PRT_NEXT();
6499 }
6500 len = asc_prt_line(cp, leftlen, "\n");
6501 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006503 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6504 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6505 ASC_PRT_NEXT();
6506 for (i = 0; i <= ADV_MAX_TID; i++) {
6507 len = asc_prt_line(cp, leftlen, " %c",
6508 (ep_3550->
6509 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6510 'Y' : 'N');
6511 ASC_PRT_NEXT();
6512 }
6513 len = asc_prt_line(cp, leftlen, "\n");
6514 ASC_PRT_NEXT();
6515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006517 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6518 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6519 ASC_PRT_NEXT();
6520 for (i = 0; i <= ADV_MAX_TID; i++) {
6521 len = asc_prt_line(cp, leftlen, " %c",
6522 (ep_3550->
6523 ultra_able & ADV_TID_TO_TIDMASK(i))
6524 ? 'Y' : 'N');
6525 ASC_PRT_NEXT();
6526 }
6527 len = asc_prt_line(cp, leftlen, "\n");
6528 ASC_PRT_NEXT();
6529 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006530
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006531 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6532 word = ep_3550->wdtr_able;
6533 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6534 word = ep_38C0800->wdtr_able;
6535 } else {
6536 word = ep_38C1600->wdtr_able;
6537 }
6538 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6539 ASC_PRT_NEXT();
6540 for (i = 0; i <= ADV_MAX_TID; i++) {
6541 len = asc_prt_line(cp, leftlen, " %c",
6542 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6543 ASC_PRT_NEXT();
6544 }
6545 len = asc_prt_line(cp, leftlen, "\n");
6546 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006547
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006548 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6549 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6550 len = asc_prt_line(cp, leftlen,
6551 " Synchronous Transfer Speed (Mhz):\n ");
6552 ASC_PRT_NEXT();
6553 for (i = 0; i <= ADV_MAX_TID; i++) {
6554 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006555
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006556 if (i == 0) {
6557 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6558 } else if (i == 4) {
6559 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6560 } else if (i == 8) {
6561 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6562 } else if (i == 12) {
6563 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6564 }
6565 switch (sdtr_speed & ADV_MAX_TID) {
6566 case 0:
6567 speed_str = "Off";
6568 break;
6569 case 1:
6570 speed_str = " 5";
6571 break;
6572 case 2:
6573 speed_str = " 10";
6574 break;
6575 case 3:
6576 speed_str = " 20";
6577 break;
6578 case 4:
6579 speed_str = " 40";
6580 break;
6581 case 5:
6582 speed_str = " 80";
6583 break;
6584 default:
6585 speed_str = "Unk";
6586 break;
6587 }
6588 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6589 ASC_PRT_NEXT();
6590 if (i == 7) {
6591 len = asc_prt_line(cp, leftlen, "\n ");
6592 ASC_PRT_NEXT();
6593 }
6594 sdtr_speed >>= 4;
6595 }
6596 len = asc_prt_line(cp, leftlen, "\n");
6597 ASC_PRT_NEXT();
6598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006599
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006600 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006601}
6602
6603/*
6604 * asc_prt_driver_conf()
6605 *
6606 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6607 * cf. asc_prt_line().
6608 *
6609 * Return the number of characters copied into 'cp'. No more than
6610 * 'cplen' characters will be copied to 'cp'.
6611 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006612static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006613{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006614 asc_board_t *boardp;
6615 int leftlen;
6616 int totlen;
6617 int len;
6618 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006619
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006620 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006621
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006622 leftlen = cplen;
6623 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006624
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006625 len = asc_prt_line(cp, leftlen,
6626 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6627 shost->host_no);
6628 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006629
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006630 len = asc_prt_line(cp, leftlen,
6631 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6632 shost->host_busy, shost->last_reset, shost->max_id,
6633 shost->max_lun, shost->max_channel);
6634 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006635
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006636 len = asc_prt_line(cp, leftlen,
6637 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6638 shost->unique_id, shost->can_queue, shost->this_id,
6639 shost->sg_tablesize, shost->cmd_per_lun);
6640 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006641
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006642 len = asc_prt_line(cp, leftlen,
6643 " unchecked_isa_dma %d, use_clustering %d\n",
6644 shost->unchecked_isa_dma, shost->use_clustering);
6645 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006646
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006647 len = asc_prt_line(cp, leftlen,
6648 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6649 boardp->flags, boardp->last_reset, jiffies,
6650 boardp->asc_n_io_port);
6651 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006652
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04006653 len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006654 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006655
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006656 if (ASC_NARROW_BOARD(boardp)) {
6657 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6658 } else {
6659 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006661
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006662 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006663}
6664
6665/*
6666 * asc_prt_asc_board_info()
6667 *
6668 * Print dynamic board configuration information.
6669 *
6670 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6671 * cf. asc_prt_line().
6672 *
6673 * Return the number of characters copied into 'cp'. No more than
6674 * 'cplen' characters will be copied to 'cp'.
6675 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006676static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006677{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006678 asc_board_t *boardp;
6679 int chip_scsi_id;
6680 int leftlen;
6681 int totlen;
6682 int len;
6683 ASC_DVC_VAR *v;
6684 ASC_DVC_CFG *c;
6685 int i;
6686 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006687
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006688 boardp = ASC_BOARDP(shost);
6689 v = &boardp->dvc_var.asc_dvc_var;
6690 c = &boardp->dvc_cfg.asc_dvc_cfg;
6691 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006692
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006693 leftlen = cplen;
6694 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006696 len = asc_prt_line(cp, leftlen,
6697 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6698 shost->host_no);
6699 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006700
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006701 len = asc_prt_line(cp, leftlen,
6702 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6703 c->chip_version, c->lib_version, c->lib_serial_no,
6704 c->mcode_date);
6705 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006706
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006707 len = asc_prt_line(cp, leftlen,
6708 " mcode_version 0x%x, err_code %u\n",
6709 c->mcode_version, v->err_code);
6710 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006711
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006712 /* Current number of commands waiting for the host. */
6713 len = asc_prt_line(cp, leftlen,
6714 " Total Command Pending: %d\n", v->cur_total_qng);
6715 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006716
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006717 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6718 ASC_PRT_NEXT();
6719 for (i = 0; i <= ASC_MAX_TID; i++) {
6720 if ((chip_scsi_id == i) ||
6721 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6722 continue;
6723 }
6724 len = asc_prt_line(cp, leftlen, " %X:%c",
6725 i,
6726 (v->
6727 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6728 'Y' : 'N');
6729 ASC_PRT_NEXT();
6730 }
6731 len = asc_prt_line(cp, leftlen, "\n");
6732 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006733
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006734 /* Current number of commands waiting for a device. */
6735 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6736 ASC_PRT_NEXT();
6737 for (i = 0; i <= ASC_MAX_TID; i++) {
6738 if ((chip_scsi_id == i) ||
6739 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6740 continue;
6741 }
6742 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6743 ASC_PRT_NEXT();
6744 }
6745 len = asc_prt_line(cp, leftlen, "\n");
6746 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006748 /* Current limit on number of commands that can be sent to a device. */
6749 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6750 ASC_PRT_NEXT();
6751 for (i = 0; i <= ASC_MAX_TID; i++) {
6752 if ((chip_scsi_id == i) ||
6753 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6754 continue;
6755 }
6756 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
6757 ASC_PRT_NEXT();
6758 }
6759 len = asc_prt_line(cp, leftlen, "\n");
6760 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006762 /* Indicate whether the device has returned queue full status. */
6763 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
6764 ASC_PRT_NEXT();
6765 for (i = 0; i <= ASC_MAX_TID; i++) {
6766 if ((chip_scsi_id == i) ||
6767 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6768 continue;
6769 }
6770 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
6771 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
6772 i, boardp->queue_full_cnt[i]);
6773 } else {
6774 len = asc_prt_line(cp, leftlen, " %X:N", i);
6775 }
6776 ASC_PRT_NEXT();
6777 }
6778 len = asc_prt_line(cp, leftlen, "\n");
6779 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006780
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006781 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6782 ASC_PRT_NEXT();
6783 for (i = 0; i <= ASC_MAX_TID; i++) {
6784 if ((chip_scsi_id == i) ||
6785 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6786 continue;
6787 }
6788 len = asc_prt_line(cp, leftlen, " %X:%c",
6789 i,
6790 (v->
6791 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6792 'N');
6793 ASC_PRT_NEXT();
6794 }
6795 len = asc_prt_line(cp, leftlen, "\n");
6796 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006797
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006798 for (i = 0; i <= ASC_MAX_TID; i++) {
6799 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006801 if ((chip_scsi_id == i) ||
6802 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6803 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
6804 continue;
6805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006806
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006807 len = asc_prt_line(cp, leftlen, " %X:", i);
6808 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006810 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
6811 len = asc_prt_line(cp, leftlen, " Asynchronous");
6812 ASC_PRT_NEXT();
6813 } else {
6814 syn_period_ix =
6815 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
6816 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006817
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006818 len = asc_prt_line(cp, leftlen,
6819 " Transfer Period Factor: %d (%d.%d Mhz),",
6820 v->sdtr_period_tbl[syn_period_ix],
6821 250 /
6822 v->sdtr_period_tbl[syn_period_ix],
6823 ASC_TENTHS(250,
6824 v->
6825 sdtr_period_tbl
6826 [syn_period_ix]));
6827 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006829 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6830 boardp->
6831 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
6832 ASC_PRT_NEXT();
6833 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006834
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006835 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6836 len = asc_prt_line(cp, leftlen, "*\n");
6837 renegotiate = 1;
6838 } else {
6839 len = asc_prt_line(cp, leftlen, "\n");
6840 }
6841 ASC_PRT_NEXT();
6842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006843
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006844 if (renegotiate) {
6845 len = asc_prt_line(cp, leftlen,
6846 " * = Re-negotiation pending before next command.\n");
6847 ASC_PRT_NEXT();
6848 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006850 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006851}
6852
6853/*
6854 * asc_prt_adv_board_info()
6855 *
6856 * Print dynamic board configuration information.
6857 *
6858 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6859 * cf. asc_prt_line().
6860 *
6861 * Return the number of characters copied into 'cp'. No more than
6862 * 'cplen' characters will be copied to 'cp'.
6863 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006864static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006865{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006866 asc_board_t *boardp;
6867 int leftlen;
6868 int totlen;
6869 int len;
6870 int i;
6871 ADV_DVC_VAR *v;
6872 ADV_DVC_CFG *c;
6873 AdvPortAddr iop_base;
6874 ushort chip_scsi_id;
6875 ushort lramword;
6876 uchar lrambyte;
6877 ushort tagqng_able;
6878 ushort sdtr_able, wdtr_able;
6879 ushort wdtr_done, sdtr_done;
6880 ushort period = 0;
6881 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006882
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006883 boardp = ASC_BOARDP(shost);
6884 v = &boardp->dvc_var.adv_dvc_var;
6885 c = &boardp->dvc_cfg.adv_dvc_cfg;
6886 iop_base = v->iop_base;
6887 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006888
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006889 leftlen = cplen;
6890 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006891
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006892 len = asc_prt_line(cp, leftlen,
6893 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6894 shost->host_no);
6895 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006896
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006897 len = asc_prt_line(cp, leftlen,
6898 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
6899 v->iop_base,
6900 AdvReadWordRegister(iop_base,
6901 IOPW_SCSI_CFG1) & CABLE_DETECT,
6902 v->err_code);
6903 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006904
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006905 len = asc_prt_line(cp, leftlen,
6906 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
6907 c->chip_version, c->lib_version, c->mcode_date,
6908 c->mcode_version);
6909 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006910
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006911 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
6912 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
6913 ASC_PRT_NEXT();
6914 for (i = 0; i <= ADV_MAX_TID; i++) {
6915 if ((chip_scsi_id == i) ||
6916 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6917 continue;
6918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006920 len = asc_prt_line(cp, leftlen, " %X:%c",
6921 i,
6922 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6923 'N');
6924 ASC_PRT_NEXT();
6925 }
6926 len = asc_prt_line(cp, leftlen, "\n");
6927 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006929 len = asc_prt_line(cp, leftlen, " Queue Limit:");
6930 ASC_PRT_NEXT();
6931 for (i = 0; i <= ADV_MAX_TID; i++) {
6932 if ((chip_scsi_id == i) ||
6933 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6934 continue;
6935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006936
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006937 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
6938 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006940 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6941 ASC_PRT_NEXT();
6942 }
6943 len = asc_prt_line(cp, leftlen, "\n");
6944 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006945
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006946 len = asc_prt_line(cp, leftlen, " Command Pending:");
6947 ASC_PRT_NEXT();
6948 for (i = 0; i <= ADV_MAX_TID; i++) {
6949 if ((chip_scsi_id == i) ||
6950 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6951 continue;
6952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006953
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006954 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
6955 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006956
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006957 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6958 ASC_PRT_NEXT();
6959 }
6960 len = asc_prt_line(cp, leftlen, "\n");
6961 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006962
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006963 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
6964 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
6965 ASC_PRT_NEXT();
6966 for (i = 0; i <= ADV_MAX_TID; i++) {
6967 if ((chip_scsi_id == i) ||
6968 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6969 continue;
6970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006971
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006972 len = asc_prt_line(cp, leftlen, " %X:%c",
6973 i,
6974 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6975 'N');
6976 ASC_PRT_NEXT();
6977 }
6978 len = asc_prt_line(cp, leftlen, "\n");
6979 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006980
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006981 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
6982 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
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 AdvReadWordLram(iop_base,
6991 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
6992 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006993
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006994 len = asc_prt_line(cp, leftlen, " %X:%d",
6995 i, (lramword & 0x8000) ? 16 : 8);
6996 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006997
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006998 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
6999 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7000 len = asc_prt_line(cp, leftlen, "*");
7001 ASC_PRT_NEXT();
7002 renegotiate = 1;
7003 }
7004 }
7005 len = asc_prt_line(cp, leftlen, "\n");
7006 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007007
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007008 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7009 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7010 ASC_PRT_NEXT();
7011 for (i = 0; i <= ADV_MAX_TID; i++) {
7012 if ((chip_scsi_id == i) ||
7013 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7014 continue;
7015 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007016
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007017 len = asc_prt_line(cp, leftlen, " %X:%c",
7018 i,
7019 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7020 'N');
7021 ASC_PRT_NEXT();
7022 }
7023 len = asc_prt_line(cp, leftlen, "\n");
7024 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007025
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007026 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7027 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007029 AdvReadWordLram(iop_base,
7030 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7031 lramword);
7032 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007033
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007034 if ((chip_scsi_id == i) ||
7035 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7036 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7037 continue;
7038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007039
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007040 len = asc_prt_line(cp, leftlen, " %X:", i);
7041 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007043 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7044 len = asc_prt_line(cp, leftlen, " Asynchronous");
7045 ASC_PRT_NEXT();
7046 } else {
7047 len =
7048 asc_prt_line(cp, leftlen,
7049 " Transfer Period Factor: ");
7050 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007051
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007052 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7053 len =
7054 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7055 ASC_PRT_NEXT();
7056 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7057 len =
7058 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7059 ASC_PRT_NEXT();
7060 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007061
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007062 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007063
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007064 if (period == 0) { /* Should never happen. */
7065 len =
7066 asc_prt_line(cp, leftlen,
7067 "%d (? Mhz), ");
7068 ASC_PRT_NEXT();
7069 } else {
7070 len = asc_prt_line(cp, leftlen,
7071 "%d (%d.%d Mhz),",
7072 period, 250 / period,
7073 ASC_TENTHS(250,
7074 period));
7075 ASC_PRT_NEXT();
7076 }
7077 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007078
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007079 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7080 lramword & 0x1F);
7081 ASC_PRT_NEXT();
7082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007083
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007084 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7085 len = asc_prt_line(cp, leftlen, "*\n");
7086 renegotiate = 1;
7087 } else {
7088 len = asc_prt_line(cp, leftlen, "\n");
7089 }
7090 ASC_PRT_NEXT();
7091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007092
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007093 if (renegotiate) {
7094 len = asc_prt_line(cp, leftlen,
7095 " * = Re-negotiation pending before next command.\n");
7096 ASC_PRT_NEXT();
7097 }
7098
7099 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007100}
7101
7102/*
7103 * asc_proc_copy()
7104 *
7105 * Copy proc information to a read buffer taking into account the current
7106 * read offset in the file and the remaining space in the read buffer.
7107 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007108static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007109asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007110 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007111{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007112 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007113
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007114 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7115 (unsigned)offset, (unsigned)advoffset, cplen);
7116 if (offset <= advoffset) {
7117 /* Read offset below current offset, copy everything. */
7118 cnt = min(cplen, leftlen);
7119 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7120 (ulong)curbuf, (ulong)cp, cnt);
7121 memcpy(curbuf, cp, cnt);
7122 } else if (offset < advoffset + cplen) {
7123 /* Read offset within current range, partial copy. */
7124 cnt = (advoffset + cplen) - offset;
7125 cp = (cp + cplen) - cnt;
7126 cnt = min(cnt, leftlen);
7127 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7128 (ulong)curbuf, (ulong)cp, cnt);
7129 memcpy(curbuf, cp, cnt);
7130 }
7131 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007132}
7133
7134/*
7135 * asc_prt_line()
7136 *
7137 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7138 *
7139 * Return 0 if printing to the console, otherwise return the number of
7140 * bytes written to the buffer.
7141 *
7142 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7143 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7144 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007145static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007146{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007147 va_list args;
7148 int ret;
7149 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007150
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007151 va_start(args, fmt);
7152 ret = vsprintf(s, fmt, args);
7153 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7154 if (buf == NULL) {
7155 (void)printk(s);
7156 ret = 0;
7157 } else {
7158 ret = min(buflen, ret);
7159 memcpy(buf, s, ret);
7160 }
7161 va_end(args);
7162 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007163}
7164#endif /* CONFIG_PROC_FS */
7165
Linus Torvalds1da177e2005-04-16 15:20:36 -07007166/*
7167 * --- Functions Required by the Asc Library
7168 */
7169
7170/*
7171 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7172 * global variable which is incremented once every 5 ms
7173 * from a timer interrupt, because this function may be
7174 * called when interrupts are disabled.
7175 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007176static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007177{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007178 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7179 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007180}
7181
7182/*
7183 * Currently and inline noop but leave as a placeholder.
7184 * Leave DvcEnterCritical() as a noop placeholder.
7185 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007186static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007187{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007188 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007189}
7190
7191/*
7192 * Critical sections are all protected by the board spinlock.
7193 * Leave DvcLeaveCritical() as a noop placeholder.
7194 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007195static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007196{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007197 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007198}
7199
7200/*
7201 * void
7202 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7203 *
7204 * Calling/Exit State:
7205 * none
7206 *
7207 * Description:
7208 * Output an ASC_SCSI_Q structure to the chip
7209 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007210static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007211DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7212{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007213 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007214
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007215 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7216 AscSetChipLramAddr(iop_base, s_addr);
7217 for (i = 0; i < 2 * words; i += 2) {
7218 if (i == 4 || i == 20) {
7219 continue;
7220 }
7221 outpw(iop_base + IOP_RAM_DATA,
7222 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007224}
7225
7226/*
7227 * void
7228 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7229 *
7230 * Calling/Exit State:
7231 * none
7232 *
7233 * Description:
7234 * Input an ASC_QDONE_INFO structure from the chip
7235 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007236static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007237DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7238{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007239 int i;
7240 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007241
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007242 AscSetChipLramAddr(iop_base, s_addr);
7243 for (i = 0; i < 2 * words; i += 2) {
7244 if (i == 10) {
7245 continue;
7246 }
7247 word = inpw(iop_base + IOP_RAM_DATA);
7248 inbuf[i] = word & 0xff;
7249 inbuf[i + 1] = (word >> 8) & 0xff;
7250 }
7251 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007252}
7253
7254/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007255 * Return the BIOS address of the adapter at the specified
7256 * I/O port and with the specified bus type.
7257 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007258static unsigned short __devinit
7259AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007260{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007261 unsigned short cfg_lsw;
7262 unsigned short bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007263
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007264 /*
7265 * The PCI BIOS is re-located by the motherboard BIOS. Because
7266 * of this the driver can not determine where a PCI BIOS is
7267 * loaded and executes.
7268 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007269 if (bus_type & ASC_IS_PCI)
7270 return 0;
7271
Linus Torvalds1da177e2005-04-16 15:20:36 -07007272#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007273 if ((bus_type & ASC_IS_EISA) != 0) {
7274 cfg_lsw = AscGetEisaChipCfg(iop_base);
7275 cfg_lsw &= 0x000F;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007276 bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
7277 return bios_addr;
7278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007279#endif /* CONFIG_ISA */
7280
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007281 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007282
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007283 /*
7284 * ISA PnP uses the top bit as the 32K BIOS flag
7285 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007286 if (bus_type == ASC_IS_ISAPNP)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007287 cfg_lsw &= 0x7FFF;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007288 bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
7289 return bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007290}
7291
Linus Torvalds1da177e2005-04-16 15:20:36 -07007292/*
7293 * --- Functions Required by the Adv Library
7294 */
7295
7296/*
7297 * DvcGetPhyAddr()
7298 *
7299 * Return the physical address of 'vaddr' and set '*lenp' to the
7300 * number of physically contiguous bytes that follow 'vaddr'.
7301 * 'flag' indicates the type of structure whose physical address
7302 * is being translated.
7303 *
7304 * Note: Because Linux currently doesn't page the kernel and all
7305 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7306 */
7307ADV_PADDR
7308DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007309 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007310{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007311 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007312
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007313 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007315 ASC_DBG4(4,
7316 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7317 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7318 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007320 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007321}
7322
7323/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007324 * --- Tracing and Debugging Functions
7325 */
7326
7327#ifdef ADVANSYS_STATS
7328#ifdef CONFIG_PROC_FS
7329/*
7330 * asc_prt_board_stats()
7331 *
7332 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7333 * cf. asc_prt_line().
7334 *
7335 * Return the number of characters copied into 'cp'. No more than
7336 * 'cplen' characters will be copied to 'cp'.
7337 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007338static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007339{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007340 int leftlen;
7341 int totlen;
7342 int len;
7343 struct asc_stats *s;
7344 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007345
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007346 leftlen = cplen;
7347 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007348
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007349 boardp = ASC_BOARDP(shost);
7350 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007351
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007352 len = asc_prt_line(cp, leftlen,
7353 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7354 shost->host_no);
7355 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007356
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007357 len = asc_prt_line(cp, leftlen,
7358 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7359 s->queuecommand, s->reset, s->biosparam,
7360 s->interrupt);
7361 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007362
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007363 len = asc_prt_line(cp, leftlen,
7364 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7365 s->callback, s->done, s->build_error,
7366 s->adv_build_noreq, s->adv_build_nosg);
7367 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007368
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007369 len = asc_prt_line(cp, leftlen,
7370 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7371 s->exe_noerror, s->exe_busy, s->exe_error,
7372 s->exe_unknown);
7373 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007374
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007375 /*
7376 * Display data transfer statistics.
7377 */
7378 if (s->cont_cnt > 0) {
7379 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7380 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007382 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7383 s->cont_xfer / 2,
7384 ASC_TENTHS(s->cont_xfer, 2));
7385 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007386
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007387 /* Contiguous transfer average size */
7388 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7389 (s->cont_xfer / 2) / s->cont_cnt,
7390 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7391 ASC_PRT_NEXT();
7392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007394 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007395
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007396 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7397 s->sg_cnt, s->sg_elem);
7398 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007399
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007400 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7401 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7402 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007403
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007404 /* Scatter gather transfer statistics */
7405 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7406 s->sg_elem / s->sg_cnt,
7407 ASC_TENTHS(s->sg_elem, s->sg_cnt));
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, "avg_elem_size %lu.%01lu kb, ",
7411 (s->sg_xfer / 2) / s->sg_elem,
7412 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7413 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007414
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007415 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7416 (s->sg_xfer / 2) / s->sg_cnt,
7417 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7418 ASC_PRT_NEXT();
7419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007420
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007421 /*
7422 * Display request queuing statistics.
7423 */
7424 len = asc_prt_line(cp, leftlen,
7425 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7426 HZ);
7427 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007428
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007429 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007430}
7431
7432/*
7433 * asc_prt_target_stats()
7434 *
7435 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7436 * cf. asc_prt_line().
7437 *
7438 * This is separated from asc_prt_board_stats because a full set
7439 * of targets will overflow ASC_PRTBUF_SIZE.
7440 *
7441 * Return the number of characters copied into 'cp'. No more than
7442 * 'cplen' characters will be copied to 'cp'.
7443 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007444static int
7445asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007446{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007447 int leftlen;
7448 int totlen;
7449 int len;
7450 struct asc_stats *s;
7451 ushort chip_scsi_id;
7452 asc_board_t *boardp;
7453 asc_queue_t *active;
7454 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007455
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007456 leftlen = cplen;
7457 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007458
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007459 boardp = ASC_BOARDP(shost);
7460 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007461
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007462 active = &ASC_BOARDP(shost)->active;
7463 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007464
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007465 if (ASC_NARROW_BOARD(boardp)) {
7466 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7467 } else {
7468 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007470
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007471 if ((chip_scsi_id == tgt_id) ||
7472 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7473 return 0;
7474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007475
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007476 do {
7477 if (active->q_tot_cnt[tgt_id] > 0
7478 || waiting->q_tot_cnt[tgt_id] > 0) {
7479 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
7480 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007481
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007482 len = asc_prt_line(cp, leftlen,
7483 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7484 active->q_cur_cnt[tgt_id],
7485 active->q_max_cnt[tgt_id],
7486 active->q_tot_cnt[tgt_id],
7487 active->q_min_tim[tgt_id],
7488 active->q_max_tim[tgt_id],
7489 (active->q_tot_cnt[tgt_id] ==
7490 0) ? 0 : (active->
7491 q_tot_tim[tgt_id] /
7492 active->
7493 q_tot_cnt[tgt_id]),
7494 (active->q_tot_cnt[tgt_id] ==
7495 0) ? 0 : ASC_TENTHS(active->
7496 q_tot_tim
7497 [tgt_id],
7498 active->
7499 q_tot_cnt
7500 [tgt_id]));
7501 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007502
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007503 len = asc_prt_line(cp, leftlen,
7504 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7505 waiting->q_cur_cnt[tgt_id],
7506 waiting->q_max_cnt[tgt_id],
7507 waiting->q_tot_cnt[tgt_id],
7508 waiting->q_min_tim[tgt_id],
7509 waiting->q_max_tim[tgt_id],
7510 (waiting->q_tot_cnt[tgt_id] ==
7511 0) ? 0 : (waiting->
7512 q_tot_tim[tgt_id] /
7513 waiting->
7514 q_tot_cnt[tgt_id]),
7515 (waiting->q_tot_cnt[tgt_id] ==
7516 0) ? 0 : ASC_TENTHS(waiting->
7517 q_tot_tim
7518 [tgt_id],
7519 waiting->
7520 q_tot_cnt
7521 [tgt_id]));
7522 ASC_PRT_NEXT();
7523 }
7524 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007525
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007526 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007527}
7528#endif /* CONFIG_PROC_FS */
7529#endif /* ADVANSYS_STATS */
7530
7531#ifdef ADVANSYS_DEBUG
7532/*
7533 * asc_prt_scsi_host()
7534 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007535static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007536{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007537 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007538
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007539 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007540
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007541 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7542 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7543 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007544
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04007545 printk(" base 0x%lx, io_port 0x%lx, irq 0x%x,\n",
7546 (ulong)s->base, (ulong)s->io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007547
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007548 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7549 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007550
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007551 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7552 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007553
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007554 if (ASC_NARROW_BOARD(boardp)) {
7555 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7556 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7557 } else {
7558 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7559 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007561}
7562
7563/*
7564 * asc_prt_scsi_cmnd()
7565 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007566static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007567{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007568 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007569
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007570 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7571 (ulong)s->device->host, (ulong)s->device, s->device->id,
7572 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007573
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007574 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007575
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007576 printk("sc_data_direction %u, resid %d\n",
7577 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007578
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007579 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007580
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007581 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7582 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007583
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007584 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007585
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007586 printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
7587 s->scsi_done, s->done, s->host_scribble, s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007588
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007589 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007590}
7591
7592/*
7593 * asc_prt_asc_dvc_var()
7594 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007595static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007596{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007597 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007598
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007599 printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
7600 "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007601
Matthew Wilcox895d6b42007-07-26 11:57:06 -04007602 printk(" bus_type %d, init_sdtr 0x%x,\n", h->bus_type,
7603 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007604
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007605 printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
7606 "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
7607 (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
7608 (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007609
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007610 printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
7611 "%u,\n", (unsigned)h->queue_full_or_busy,
7612 (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007613
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007614 printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
7615 "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
7616 (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
7617 (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007618
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007619 printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
7620 "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
7621 (unsigned)h->init_state, (unsigned)h->no_scam,
7622 (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007623
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007624 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007625}
7626
7627/*
7628 * asc_prt_asc_dvc_cfg()
7629 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007630static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007631{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007632 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007633
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007634 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7635 h->can_tagged_qng, h->cmd_qng_enabled);
7636 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7637 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007638
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007639 printk
7640 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7641 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7642 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007643
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007644 printk
7645 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7646 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7647 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007648
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007649 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7650 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007651}
7652
7653/*
7654 * asc_prt_asc_scsi_q()
7655 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007656static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007657{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007658 ASC_SG_HEAD *sgp;
7659 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007660
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007661 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007662
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007663 printk
7664 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7665 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7666 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007668 printk
7669 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7670 (ulong)le32_to_cpu(q->q1.data_addr),
7671 (ulong)le32_to_cpu(q->q1.data_cnt),
7672 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007673
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007674 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
7675 (ulong)q->cdbptr, q->q2.cdb_len,
7676 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007677
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007678 if (q->sg_head) {
7679 sgp = q->sg_head;
7680 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
7681 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
7682 sgp->queue_cnt);
7683 for (i = 0; i < sgp->entry_cnt; i++) {
7684 printk(" [%u]: addr 0x%lx, bytes %lu\n",
7685 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
7686 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
7687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007688
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007690}
7691
7692/*
7693 * asc_prt_asc_qdone_info()
7694 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007695static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007696{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007697 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
7698 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
7699 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
7700 q->d2.tag_code);
7701 printk
7702 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
7703 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007704}
7705
7706/*
7707 * asc_prt_adv_dvc_var()
7708 *
7709 * Display an ADV_DVC_VAR structure.
7710 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007711static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007712{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007713 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007714
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007715 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
7716 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007717
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007718 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
7719 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
7720 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007721
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007722 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
7723 (unsigned)h->start_motor,
7724 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007725
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007726 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
7727 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
7728 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007729
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007730 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
7731 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007732
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007733 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
7734 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007735
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007736 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
7737 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007738}
7739
7740/*
7741 * asc_prt_adv_dvc_cfg()
7742 *
7743 * Display an ADV_DVC_CFG structure.
7744 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007745static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007746{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007747 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007748
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007749 printk(" disc_enable 0x%x, termination 0x%x\n",
7750 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007752 printk(" chip_version 0x%x, mcode_date 0x%x\n",
7753 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007754
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007755 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
7756 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007757
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06007758 printk(" control_flag 0x%x\n", h->control_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007759}
7760
7761/*
7762 * asc_prt_adv_scsi_req_q()
7763 *
7764 * Display an ADV_SCSI_REQ_Q structure.
7765 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007766static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007767{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007768 int sg_blk_cnt;
7769 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007770
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007771 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007772
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007773 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
7774 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007776 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
7777 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007778
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007779 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7780 (ulong)le32_to_cpu(q->data_cnt),
7781 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007782
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007783 printk
7784 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
7785 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007787 printk(" sg_working_ix 0x%x, target_cmd %u\n",
7788 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007790 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
7791 (ulong)le32_to_cpu(q->scsiq_rptr),
7792 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007793
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007794 /* Display the request's ADV_SG_BLOCK structures. */
7795 if (q->sg_list_ptr != NULL) {
7796 sg_blk_cnt = 0;
7797 while (1) {
7798 /*
7799 * 'sg_ptr' is a physical address. Convert it to a virtual
7800 * address by indexing 'sg_blk_cnt' into the virtual address
7801 * array 'sg_list_ptr'.
7802 *
7803 * XXX - Assumes all SG physical blocks are virtually contiguous.
7804 */
7805 sg_ptr =
7806 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
7807 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
7808 if (sg_ptr->sg_ptr == 0) {
7809 break;
7810 }
7811 sg_blk_cnt++;
7812 }
7813 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007814}
7815
7816/*
7817 * asc_prt_adv_sgblock()
7818 *
7819 * Display an ADV_SG_BLOCK structure.
7820 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007821static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007822{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007823 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007824
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007825 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
7826 (ulong)b, sgblockno);
7827 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
7828 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
7829 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
7830 if (b->sg_ptr != 0) {
7831 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
7832 }
7833 for (i = 0; i < b->sg_cnt; i++) {
7834 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
7835 i, (ulong)b->sg_list[i].sg_addr,
7836 (ulong)b->sg_list[i].sg_count);
7837 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007838}
7839
7840/*
7841 * asc_prt_hex()
7842 *
7843 * Print hexadecimal output in 4 byte groupings 32 bytes
7844 * or 8 double-words per line.
7845 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007846static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007847{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007848 int i;
7849 int j;
7850 int k;
7851 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007852
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007853 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007854
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007855 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007857 /* Display a maximum of 8 double-words per line. */
7858 if ((k = (l - i) / 4) >= 8) {
7859 k = 8;
7860 m = 0;
7861 } else {
7862 m = (l - i) % 4;
7863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007864
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007865 for (j = 0; j < k; j++) {
7866 printk(" %2.2X%2.2X%2.2X%2.2X",
7867 (unsigned)s[i + (j * 4)],
7868 (unsigned)s[i + (j * 4) + 1],
7869 (unsigned)s[i + (j * 4) + 2],
7870 (unsigned)s[i + (j * 4) + 3]);
7871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007872
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007873 switch (m) {
7874 case 0:
7875 default:
7876 break;
7877 case 1:
7878 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
7879 break;
7880 case 2:
7881 printk(" %2.2X%2.2X",
7882 (unsigned)s[i + (j * 4)],
7883 (unsigned)s[i + (j * 4) + 1]);
7884 break;
7885 case 3:
7886 printk(" %2.2X%2.2X%2.2X",
7887 (unsigned)s[i + (j * 4) + 1],
7888 (unsigned)s[i + (j * 4) + 2],
7889 (unsigned)s[i + (j * 4) + 3]);
7890 break;
7891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007892
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007893 printk("\n");
7894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007895}
7896#endif /* ADVANSYS_DEBUG */
7897
7898/*
7899 * --- Asc Library Functions
7900 */
7901
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007902static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007903{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007904 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007905
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007906 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7907 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
7908 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007909}
7910
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007911static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007912{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007913 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007914
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007915 if (AscGetChipScsiID(iop_base) == new_host_id) {
7916 return (new_host_id);
7917 }
7918 cfg_lsw = AscGetChipCfgLsw(iop_base);
7919 cfg_lsw &= 0xF8FF;
7920 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
7921 AscSetChipCfgLsw(iop_base, cfg_lsw);
7922 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007923}
7924
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007925static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007926{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007927 unsigned char sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007929 AscSetBank(iop_base, 1);
7930 sc = inp(iop_base + IOP_REG_SC);
7931 AscSetBank(iop_base, 0);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007932 return sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007933}
7934
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007935static unsigned char __devinit
7936AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007937{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007938 if (bus_type & ASC_IS_EISA) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007939 PortAddr eisa_iop;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007940 unsigned char revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007941 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7942 (PortAddr) ASC_EISA_REV_IOP_MASK;
7943 revision = inp(eisa_iop);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007944 return ASC_CHIP_MIN_VER_EISA - 1 + revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007945 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007946 return AscGetChipVerNo(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007947}
7948
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007949static ASC_DCNT
7950AscLoadMicroCode(PortAddr iop_base,
7951 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007952{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007953 ASC_DCNT chksum;
7954 ushort mcode_word_size;
7955 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007956
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007957 /* Write the microcode buffer starting at LRAM address 0. */
7958 mcode_word_size = (ushort)(mcode_size >> 1);
7959 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
7960 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007961
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007962 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
7963 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
7964 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
7965 (ushort)ASC_CODE_SEC_BEG,
7966 (ushort)((mcode_size -
7967 s_addr - (ushort)
7968 ASC_CODE_SEC_BEG) /
7969 2));
7970 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
7971 (ulong)mcode_chksum);
7972 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
7973 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
7974 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007975}
7976
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007977static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007978{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007979 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007980
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007981 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
7982 iop_base, AscGetChipSignatureByte(iop_base));
7983 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
7984 ASC_DBG2(1,
7985 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
7986 iop_base, AscGetChipSignatureWord(iop_base));
7987 sig_word = AscGetChipSignatureWord(iop_base);
7988 if ((sig_word == (ushort)ASC_1000_ID0W) ||
7989 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
7990 return (1);
7991 }
7992 }
7993 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007994}
7995
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007996static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007997{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007998 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
7999 AscSetChipStatus(iop_base, 0);
8000 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008001}
8002
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008003static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008004{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008005 ushort cfg_lsw;
8006 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008007
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008008 if ((bus_type & ASC_IS_EISA) != 0) {
8009 cfg_lsw = AscGetEisaChipCfg(iop_base);
8010 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8011 if ((chip_irq == 13) || (chip_irq > 15)) {
8012 return (0);
8013 }
8014 return (chip_irq);
8015 }
8016 if ((bus_type & ASC_IS_VL) != 0) {
8017 cfg_lsw = AscGetChipCfgLsw(iop_base);
8018 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8019 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8020 return (0);
8021 }
8022 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8023 }
8024 cfg_lsw = AscGetChipCfgLsw(iop_base);
8025 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8026 if (chip_irq == 3)
8027 chip_irq += (uchar)2;
8028 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008029}
8030
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008031static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008032AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008033{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008034 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008035
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008036 if ((bus_type & ASC_IS_VL) != 0) {
8037 if (irq_no != 0) {
8038 if ((irq_no < ASC_MIN_IRQ_NO)
8039 || (irq_no > ASC_MAX_IRQ_NO)) {
8040 irq_no = 0;
8041 } else {
8042 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8043 }
8044 }
8045 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8046 cfg_lsw |= (ushort)0x0010;
8047 AscSetChipCfgLsw(iop_base, cfg_lsw);
8048 AscToggleIRQAct(iop_base);
8049 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8050 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8051 AscSetChipCfgLsw(iop_base, cfg_lsw);
8052 AscToggleIRQAct(iop_base);
8053 return (AscGetChipIRQ(iop_base, bus_type));
8054 }
8055 if ((bus_type & (ASC_IS_ISA)) != 0) {
8056 if (irq_no == 15)
8057 irq_no -= (uchar)2;
8058 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8059 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8060 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8061 AscSetChipCfgLsw(iop_base, cfg_lsw);
8062 return (AscGetChipIRQ(iop_base, bus_type));
8063 }
8064 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008065}
8066
8067#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008068static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008069{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008070 if (dma_channel < 4) {
8071 outp(0x000B, (ushort)(0xC0 | dma_channel));
8072 outp(0x000A, dma_channel);
8073 } else if (dma_channel < 8) {
8074 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8075 outp(0x00D4, (ushort)(dma_channel - 4));
8076 }
8077 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008078}
8079#endif /* CONFIG_ISA */
8080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008081static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008082{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008083 EXT_MSG ext_msg;
8084 EXT_MSG out_msg;
8085 ushort halt_q_addr;
8086 int sdtr_accept;
8087 ushort int_halt_code;
8088 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8089 ASC_SCSI_BIT_ID_TYPE target_id;
8090 PortAddr iop_base;
8091 uchar tag_code;
8092 uchar q_status;
8093 uchar halt_qp;
8094 uchar sdtr_data;
8095 uchar target_ix;
8096 uchar q_cntl, tid_no;
8097 uchar cur_dvc_qng;
8098 uchar asyn_sdtr;
8099 uchar scsi_status;
8100 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008101
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008102 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8103 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008105 iop_base = asc_dvc->iop_base;
8106 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008107
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008108 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8109 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8110 target_ix = AscReadLramByte(iop_base,
8111 (ushort)(halt_q_addr +
8112 (ushort)ASC_SCSIQ_B_TARGET_IX));
8113 q_cntl =
8114 AscReadLramByte(iop_base,
8115 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8116 tid_no = ASC_TIX_TO_TID(target_ix);
8117 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8118 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8119 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8120 } else {
8121 asyn_sdtr = 0;
8122 }
8123 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8124 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8125 AscSetChipSDTR(iop_base, 0, tid_no);
8126 boardp->sdtr_data[tid_no] = 0;
8127 }
8128 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8129 return (0);
8130 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8131 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8132 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8133 boardp->sdtr_data[tid_no] = asyn_sdtr;
8134 }
8135 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8136 return (0);
8137 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008138
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008139 AscMemWordCopyPtrFromLram(iop_base,
8140 ASCV_MSGIN_BEG,
8141 (uchar *)&ext_msg,
8142 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008143
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008144 if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8145 ext_msg.msg_req == EXTENDED_SDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008146 ext_msg.msg_len == MS_SDTR_LEN) {
8147 sdtr_accept = TRUE;
8148 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008149
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008150 sdtr_accept = FALSE;
8151 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8152 }
8153 if ((ext_msg.xfer_period <
8154 asc_dvc->sdtr_period_tbl[asc_dvc->
8155 host_init_sdtr_index])
8156 || (ext_msg.xfer_period >
8157 asc_dvc->sdtr_period_tbl[asc_dvc->
8158 max_sdtr_index])) {
8159 sdtr_accept = FALSE;
8160 ext_msg.xfer_period =
8161 asc_dvc->sdtr_period_tbl[asc_dvc->
8162 host_init_sdtr_index];
8163 }
8164 if (sdtr_accept) {
8165 sdtr_data =
8166 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8167 ext_msg.req_ack_offset);
8168 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008170 q_cntl |= QC_MSG_OUT;
8171 asc_dvc->init_sdtr &= ~target_id;
8172 asc_dvc->sdtr_done &= ~target_id;
8173 AscSetChipSDTR(iop_base, asyn_sdtr,
8174 tid_no);
8175 boardp->sdtr_data[tid_no] = asyn_sdtr;
8176 }
8177 }
8178 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008179
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008180 q_cntl &= ~QC_MSG_OUT;
8181 asc_dvc->init_sdtr &= ~target_id;
8182 asc_dvc->sdtr_done &= ~target_id;
8183 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8184 } else {
8185 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008186
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008187 q_cntl &= ~QC_MSG_OUT;
8188 asc_dvc->sdtr_done |= target_id;
8189 asc_dvc->init_sdtr |= target_id;
8190 asc_dvc->pci_fix_asyn_xfer &=
8191 ~target_id;
8192 sdtr_data =
8193 AscCalSDTRData(asc_dvc,
8194 ext_msg.xfer_period,
8195 ext_msg.
8196 req_ack_offset);
8197 AscSetChipSDTR(iop_base, sdtr_data,
8198 tid_no);
8199 boardp->sdtr_data[tid_no] = sdtr_data;
8200 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008201
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008202 q_cntl |= QC_MSG_OUT;
8203 AscMsgOutSDTR(asc_dvc,
8204 ext_msg.xfer_period,
8205 ext_msg.req_ack_offset);
8206 asc_dvc->pci_fix_asyn_xfer &=
8207 ~target_id;
8208 sdtr_data =
8209 AscCalSDTRData(asc_dvc,
8210 ext_msg.xfer_period,
8211 ext_msg.
8212 req_ack_offset);
8213 AscSetChipSDTR(iop_base, sdtr_data,
8214 tid_no);
8215 boardp->sdtr_data[tid_no] = sdtr_data;
8216 asc_dvc->sdtr_done |= target_id;
8217 asc_dvc->init_sdtr |= target_id;
8218 }
8219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008220
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008221 AscWriteLramByte(iop_base,
8222 (ushort)(halt_q_addr +
8223 (ushort)ASC_SCSIQ_B_CNTL),
8224 q_cntl);
8225 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8226 return (0);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008227 } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8228 ext_msg.msg_req == EXTENDED_WDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008229 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008230
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008231 ext_msg.wdtr_width = 0;
8232 AscMemWordCopyPtrToLram(iop_base,
8233 ASCV_MSGOUT_BEG,
8234 (uchar *)&ext_msg,
8235 sizeof(EXT_MSG) >> 1);
8236 q_cntl |= QC_MSG_OUT;
8237 AscWriteLramByte(iop_base,
8238 (ushort)(halt_q_addr +
8239 (ushort)ASC_SCSIQ_B_CNTL),
8240 q_cntl);
8241 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8242 return (0);
8243 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008244
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008245 ext_msg.msg_type = MESSAGE_REJECT;
8246 AscMemWordCopyPtrToLram(iop_base,
8247 ASCV_MSGOUT_BEG,
8248 (uchar *)&ext_msg,
8249 sizeof(EXT_MSG) >> 1);
8250 q_cntl |= QC_MSG_OUT;
8251 AscWriteLramByte(iop_base,
8252 (ushort)(halt_q_addr +
8253 (ushort)ASC_SCSIQ_B_CNTL),
8254 q_cntl);
8255 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8256 return (0);
8257 }
8258 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008259
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008260 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008261
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008262 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008263
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008264 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008265
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008266 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8267 q_cntl |= QC_MSG_OUT;
8268 AscMsgOutSDTR(asc_dvc,
8269 asc_dvc->
8270 sdtr_period_tbl[(sdtr_data >> 4) &
8271 (uchar)(asc_dvc->
8272 max_sdtr_index -
8273 1)],
8274 (uchar)(sdtr_data & (uchar)
8275 ASC_SYN_MAX_OFFSET));
8276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008277
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008278 AscWriteLramByte(iop_base,
8279 (ushort)(halt_q_addr +
8280 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008281
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008282 tag_code = AscReadLramByte(iop_base,
8283 (ushort)(halt_q_addr + (ushort)
8284 ASC_SCSIQ_B_TAG_CODE));
8285 tag_code &= 0xDC;
8286 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8287 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8288 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008289
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008290 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8291 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008292
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008293 }
8294 AscWriteLramByte(iop_base,
8295 (ushort)(halt_q_addr +
8296 (ushort)ASC_SCSIQ_B_TAG_CODE),
8297 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008298
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008299 q_status = AscReadLramByte(iop_base,
8300 (ushort)(halt_q_addr + (ushort)
8301 ASC_SCSIQ_B_STATUS));
8302 q_status |= (QS_READY | QS_BUSY);
8303 AscWriteLramByte(iop_base,
8304 (ushort)(halt_q_addr +
8305 (ushort)ASC_SCSIQ_B_STATUS),
8306 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008307
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008308 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8309 scsi_busy &= ~target_id;
8310 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008311
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008312 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8313 return (0);
8314 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008315
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008316 AscMemWordCopyPtrFromLram(iop_base,
8317 ASCV_MSGOUT_BEG,
8318 (uchar *)&out_msg,
8319 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008320
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008321 if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008322 (out_msg.msg_len == MS_SDTR_LEN) &&
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008323 (out_msg.msg_req == EXTENDED_SDTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008324
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008325 asc_dvc->init_sdtr &= ~target_id;
8326 asc_dvc->sdtr_done &= ~target_id;
8327 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8328 boardp->sdtr_data[tid_no] = asyn_sdtr;
8329 }
8330 q_cntl &= ~QC_MSG_OUT;
8331 AscWriteLramByte(iop_base,
8332 (ushort)(halt_q_addr +
8333 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8334 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8335 return (0);
8336 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008337
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008338 scsi_status = AscReadLramByte(iop_base,
8339 (ushort)((ushort)halt_q_addr +
8340 (ushort)
8341 ASC_SCSIQ_SCSI_STATUS));
8342 cur_dvc_qng =
8343 AscReadLramByte(iop_base,
8344 (ushort)((ushort)ASC_QADR_BEG +
8345 (ushort)target_ix));
8346 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008347
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008348 scsi_busy = AscReadLramByte(iop_base,
8349 (ushort)ASCV_SCSIBUSY_B);
8350 scsi_busy |= target_id;
8351 AscWriteLramByte(iop_base,
8352 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8353 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008354
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008355 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8356 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8357 cur_dvc_qng -= 1;
8358 asc_dvc->max_dvc_qng[tid_no] =
8359 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008360
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008361 AscWriteLramByte(iop_base,
8362 (ushort)((ushort)
8363 ASCV_MAX_DVC_QNG_BEG
8364 + (ushort)
8365 tid_no),
8366 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008367
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008368 /*
8369 * Set the device queue depth to the number of
8370 * active requests when the QUEUE FULL condition
8371 * was encountered.
8372 */
8373 boardp->queue_full |= target_id;
8374 boardp->queue_full_cnt[tid_no] =
8375 cur_dvc_qng;
8376 }
8377 }
8378 }
8379 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8380 return (0);
8381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008382#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008383 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8384 uchar q_no;
8385 ushort q_addr;
8386 uchar sg_wk_q_no;
8387 uchar first_sg_wk_q_no;
8388 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8389 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8390 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8391 ushort sg_list_dwords;
8392 ushort sg_entry_cnt;
8393 uchar next_qp;
8394 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008395
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008396 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8397 if (q_no == ASC_QLINK_END) {
8398 return (0);
8399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008400
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008401 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008403 /*
8404 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8405 * structure pointer using a macro provided by the driver.
8406 * The ASC_SCSI_REQ pointer provides a pointer to the
8407 * host ASC_SG_HEAD structure.
8408 */
8409 /* Read request's SRB pointer. */
8410 scsiq = (ASC_SCSI_Q *)
8411 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8412 (ushort)
8413 (q_addr +
8414 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008415
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008416 /*
8417 * Get request's first and working SG queue.
8418 */
8419 sg_wk_q_no = AscReadLramByte(iop_base,
8420 (ushort)(q_addr +
8421 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008422
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008423 first_sg_wk_q_no = AscReadLramByte(iop_base,
8424 (ushort)(q_addr +
8425 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008426
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008427 /*
8428 * Reset request's working SG queue back to the
8429 * first SG queue.
8430 */
8431 AscWriteLramByte(iop_base,
8432 (ushort)(q_addr +
8433 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8434 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008436 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008437
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008438 /*
8439 * Set sg_entry_cnt to the number of SG elements
8440 * that will be completed on this interrupt.
8441 *
8442 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8443 * SG elements. The data_cnt and data_addr fields which
8444 * add 1 to the SG element capacity are not used when
8445 * restarting SG handling after a halt.
8446 */
8447 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8448 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008450 /*
8451 * Keep track of remaining number of SG elements that will
8452 * need to be handled on the next interrupt.
8453 */
8454 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8455 } else {
8456 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8457 scsiq->remain_sg_entry_cnt = 0;
8458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008459
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008460 /*
8461 * Copy SG elements into the list of allocated SG queues.
8462 *
8463 * Last index completed is saved in scsiq->next_sg_index.
8464 */
8465 next_qp = first_sg_wk_q_no;
8466 q_addr = ASC_QNO_TO_QADDR(next_qp);
8467 scsi_sg_q.sg_head_qp = q_no;
8468 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8469 for (i = 0; i < sg_head->queue_cnt; i++) {
8470 scsi_sg_q.seq_no = i + 1;
8471 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8472 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8473 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8474 /*
8475 * After very first SG queue RISC FW uses next
8476 * SG queue first element then checks sg_list_cnt
8477 * against zero and then decrements, so set
8478 * sg_list_cnt 1 less than number of SG elements
8479 * in each SG queue.
8480 */
8481 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8482 scsi_sg_q.sg_cur_list_cnt =
8483 ASC_SG_LIST_PER_Q - 1;
8484 } else {
8485 /*
8486 * This is the last SG queue in the list of
8487 * allocated SG queues. If there are more
8488 * SG elements than will fit in the allocated
8489 * queues, then set the QCSG_SG_XFER_MORE flag.
8490 */
8491 if (scsiq->remain_sg_entry_cnt != 0) {
8492 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8493 } else {
8494 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8495 }
8496 /* equals sg_entry_cnt * 2 */
8497 sg_list_dwords = sg_entry_cnt << 1;
8498 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8499 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8500 sg_entry_cnt = 0;
8501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008502
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008503 scsi_sg_q.q_no = next_qp;
8504 AscMemWordCopyPtrToLram(iop_base,
8505 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8506 (uchar *)&scsi_sg_q,
8507 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008508
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008509 AscMemDWordCopyPtrToLram(iop_base,
8510 q_addr + ASC_SGQ_LIST_BEG,
8511 (uchar *)&sg_head->
8512 sg_list[scsiq->next_sg_index],
8513 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008514
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008515 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008516
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008517 /*
8518 * If the just completed SG queue contained the
8519 * last SG element, then no more SG queues need
8520 * to be written.
8521 */
8522 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8523 break;
8524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008525
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008526 next_qp = AscReadLramByte(iop_base,
8527 (ushort)(q_addr +
8528 ASC_SCSIQ_B_FWD));
8529 q_addr = ASC_QNO_TO_QADDR(next_qp);
8530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008531
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008532 /*
8533 * Clear the halt condition so the RISC will be restarted
8534 * after the return.
8535 */
8536 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8537 return (0);
8538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008539#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008540 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008541}
8542
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008543static uchar
8544_AscCopyLramScsiDoneQ(PortAddr iop_base,
8545 ushort q_addr,
8546 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008547{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008548 ushort _val;
8549 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008550
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008551 DvcGetQinfo(iop_base,
8552 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8553 (uchar *)scsiq,
8554 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008555
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008556 _val = AscReadLramWord(iop_base,
8557 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8558 scsiq->q_status = (uchar)_val;
8559 scsiq->q_no = (uchar)(_val >> 8);
8560 _val = AscReadLramWord(iop_base,
8561 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8562 scsiq->cntl = (uchar)_val;
8563 sg_queue_cnt = (uchar)(_val >> 8);
8564 _val = AscReadLramWord(iop_base,
8565 (ushort)(q_addr +
8566 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8567 scsiq->sense_len = (uchar)_val;
8568 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008569
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008570 /*
8571 * Read high word of remain bytes from alternate location.
8572 */
8573 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
8574 (ushort)(q_addr +
8575 (ushort)
8576 ASC_SCSIQ_W_ALT_DC1)))
8577 << 16);
8578 /*
8579 * Read low word of remain bytes from original location.
8580 */
8581 scsiq->remain_bytes += AscReadLramWord(iop_base,
8582 (ushort)(q_addr + (ushort)
8583 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008584
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008585 scsiq->remain_bytes &= max_dma_count;
8586 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008587}
8588
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008589static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008590{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008591 uchar next_qp;
8592 uchar n_q_used;
8593 uchar sg_list_qp;
8594 uchar sg_queue_cnt;
8595 uchar q_cnt;
8596 uchar done_q_tail;
8597 uchar tid_no;
8598 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8599 ASC_SCSI_BIT_ID_TYPE target_id;
8600 PortAddr iop_base;
8601 ushort q_addr;
8602 ushort sg_q_addr;
8603 uchar cur_target_qng;
8604 ASC_QDONE_INFO scsiq_buf;
8605 ASC_QDONE_INFO *scsiq;
8606 int false_overrun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008607
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008608 iop_base = asc_dvc->iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008609 n_q_used = 1;
8610 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
8611 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
8612 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
8613 next_qp = AscReadLramByte(iop_base,
8614 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
8615 if (next_qp != ASC_QLINK_END) {
8616 AscPutVarDoneQTail(iop_base, next_qp);
8617 q_addr = ASC_QNO_TO_QADDR(next_qp);
8618 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
8619 asc_dvc->max_dma_count);
8620 AscWriteLramByte(iop_base,
8621 (ushort)(q_addr +
8622 (ushort)ASC_SCSIQ_B_STATUS),
8623 (uchar)(scsiq->
8624 q_status & (uchar)~(QS_READY |
8625 QS_ABORTED)));
8626 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
8627 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
8628 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
8629 sg_q_addr = q_addr;
8630 sg_list_qp = next_qp;
8631 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
8632 sg_list_qp = AscReadLramByte(iop_base,
8633 (ushort)(sg_q_addr
8634 + (ushort)
8635 ASC_SCSIQ_B_FWD));
8636 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
8637 if (sg_list_qp == ASC_QLINK_END) {
8638 AscSetLibErrorCode(asc_dvc,
8639 ASCQ_ERR_SG_Q_LINKS);
8640 scsiq->d3.done_stat = QD_WITH_ERROR;
8641 scsiq->d3.host_stat =
8642 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
8643 goto FATAL_ERR_QDONE;
8644 }
8645 AscWriteLramByte(iop_base,
8646 (ushort)(sg_q_addr + (ushort)
8647 ASC_SCSIQ_B_STATUS),
8648 QS_FREE);
8649 }
8650 n_q_used = sg_queue_cnt + 1;
8651 AscPutVarDoneQTail(iop_base, sg_list_qp);
8652 }
8653 if (asc_dvc->queue_full_or_busy & target_id) {
8654 cur_target_qng = AscReadLramByte(iop_base,
8655 (ushort)((ushort)
8656 ASC_QADR_BEG
8657 + (ushort)
8658 scsiq->d2.
8659 target_ix));
8660 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
8661 scsi_busy = AscReadLramByte(iop_base, (ushort)
8662 ASCV_SCSIBUSY_B);
8663 scsi_busy &= ~target_id;
8664 AscWriteLramByte(iop_base,
8665 (ushort)ASCV_SCSIBUSY_B,
8666 scsi_busy);
8667 asc_dvc->queue_full_or_busy &= ~target_id;
8668 }
8669 }
8670 if (asc_dvc->cur_total_qng >= n_q_used) {
8671 asc_dvc->cur_total_qng -= n_q_used;
8672 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
8673 asc_dvc->cur_dvc_qng[tid_no]--;
8674 }
8675 } else {
8676 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
8677 scsiq->d3.done_stat = QD_WITH_ERROR;
8678 goto FATAL_ERR_QDONE;
8679 }
8680 if ((scsiq->d2.srb_ptr == 0UL) ||
8681 ((scsiq->q_status & QS_ABORTED) != 0)) {
8682 return (0x11);
8683 } else if (scsiq->q_status == QS_DONE) {
8684 false_overrun = FALSE;
8685 if (scsiq->extra_bytes != 0) {
8686 scsiq->remain_bytes +=
8687 (ADV_DCNT)scsiq->extra_bytes;
8688 }
8689 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
8690 if (scsiq->d3.host_stat ==
8691 QHSTA_M_DATA_OVER_RUN) {
8692 if ((scsiq->
8693 cntl & (QC_DATA_IN | QC_DATA_OUT))
8694 == 0) {
8695 scsiq->d3.done_stat =
8696 QD_NO_ERROR;
8697 scsiq->d3.host_stat =
8698 QHSTA_NO_ERROR;
8699 } else if (false_overrun) {
8700 scsiq->d3.done_stat =
8701 QD_NO_ERROR;
8702 scsiq->d3.host_stat =
8703 QHSTA_NO_ERROR;
8704 }
8705 } else if (scsiq->d3.host_stat ==
8706 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
8707 AscStopChip(iop_base);
8708 AscSetChipControl(iop_base,
8709 (uchar)(CC_SCSI_RESET
8710 | CC_HALT));
8711 DvcDelayNanoSecond(asc_dvc, 60000);
8712 AscSetChipControl(iop_base, CC_HALT);
8713 AscSetChipStatus(iop_base,
8714 CIW_CLR_SCSI_RESET_INT);
8715 AscSetChipStatus(iop_base, 0);
8716 AscSetChipControl(iop_base, 0);
8717 }
8718 }
8719 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04008720 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008721 } else {
8722 if ((AscReadLramByte(iop_base,
8723 (ushort)(q_addr + (ushort)
8724 ASC_SCSIQ_CDB_BEG))
8725 == START_STOP)) {
8726 asc_dvc->unit_not_ready &= ~target_id;
8727 if (scsiq->d3.done_stat != QD_NO_ERROR) {
8728 asc_dvc->start_motor &=
8729 ~target_id;
8730 }
8731 }
8732 }
8733 return (1);
8734 } else {
8735 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
8736 FATAL_ERR_QDONE:
8737 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04008738 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008739 }
8740 return (0x80);
8741 }
8742 }
8743 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008744}
8745
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008746static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008747{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008748 ASC_CS_TYPE chipstat;
8749 PortAddr iop_base;
8750 ushort saved_ram_addr;
8751 uchar ctrl_reg;
8752 uchar saved_ctrl_reg;
8753 int int_pending;
8754 int status;
8755 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008756
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008757 iop_base = asc_dvc->iop_base;
8758 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008759
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008760 if (AscIsIntPending(iop_base) == 0) {
8761 return int_pending;
8762 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008763
Matthew Wilcox895d6b42007-07-26 11:57:06 -04008764 if ((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008765 return (ERR);
8766 }
8767 if (asc_dvc->in_critical_cnt != 0) {
8768 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
8769 return (ERR);
8770 }
8771 if (asc_dvc->is_in_int) {
8772 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
8773 return (ERR);
8774 }
8775 asc_dvc->is_in_int = TRUE;
8776 ctrl_reg = AscGetChipControl(iop_base);
8777 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
8778 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
8779 chipstat = AscGetChipStatus(iop_base);
8780 if (chipstat & CSW_SCSI_RESET_LATCH) {
8781 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
8782 int i = 10;
8783 int_pending = TRUE;
8784 asc_dvc->sdtr_done = 0;
8785 saved_ctrl_reg &= (uchar)(~CC_HALT);
8786 while ((AscGetChipStatus(iop_base) &
8787 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
8788 DvcSleepMilliSecond(100);
8789 }
8790 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
8791 AscSetChipControl(iop_base, CC_HALT);
8792 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
8793 AscSetChipStatus(iop_base, 0);
8794 chipstat = AscGetChipStatus(iop_base);
8795 }
8796 }
8797 saved_ram_addr = AscGetChipLramAddr(iop_base);
8798 host_flag = AscReadLramByte(iop_base,
8799 ASCV_HOST_FLAG_B) &
8800 (uchar)(~ASC_HOST_FLAG_IN_ISR);
8801 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
8802 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
8803 if ((chipstat & CSW_INT_PENDING)
8804 || (int_pending)
8805 ) {
8806 AscAckInterrupt(iop_base);
8807 int_pending = TRUE;
8808 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
8809 if (AscIsrChipHalted(asc_dvc) == ERR) {
8810 goto ISR_REPORT_QDONE_FATAL_ERROR;
8811 } else {
8812 saved_ctrl_reg &= (uchar)(~CC_HALT);
8813 }
8814 } else {
8815 ISR_REPORT_QDONE_FATAL_ERROR:
8816 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
8817 while (((status =
8818 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
8819 }
8820 } else {
8821 do {
8822 if ((status =
8823 AscIsrQDone(asc_dvc)) == 1) {
8824 break;
8825 }
8826 } while (status == 0x11);
8827 }
8828 if ((status & 0x80) != 0)
8829 int_pending = ERR;
8830 }
8831 }
8832 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
8833 AscSetChipLramAddr(iop_base, saved_ram_addr);
8834 AscSetChipControl(iop_base, saved_ctrl_reg);
8835 asc_dvc->is_in_int = FALSE;
8836 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008837}
8838
8839/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008840static uchar _asc_mcode_buf[] = {
8841 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8842 0x00, 0x00, 0x00, 0x00,
8843 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
8844 0x00, 0x00, 0x00, 0x00,
8845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8846 0x00, 0x00, 0x00, 0x00,
8847 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8848 0x00, 0x00, 0x00, 0x00,
8849 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
8850 0x00, 0xFF, 0x00, 0x00,
8851 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
8852 0x00, 0x00, 0x00, 0x00,
8853 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
8854 0x00, 0x00, 0x00, 0x00,
8855 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
8856 0x00, 0x00, 0x00, 0x00,
8857 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
8858 0x03, 0x23, 0x36, 0x40,
8859 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
8860 0xC2, 0x00, 0x92, 0x80,
8861 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
8862 0xB6, 0x00, 0x92, 0x80,
8863 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
8864 0x92, 0x80, 0x80, 0x62,
8865 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
8866 0xCD, 0x04, 0x4D, 0x00,
8867 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
8868 0xE6, 0x84, 0xD2, 0xC1,
8869 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
8870 0xC6, 0x81, 0xC2, 0x88,
8871 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
8872 0x84, 0x97, 0x07, 0xA6,
8873 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
8874 0xC2, 0x88, 0xCE, 0x00,
8875 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
8876 0x80, 0x63, 0x07, 0xA6,
8877 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
8878 0x34, 0x01, 0x00, 0x33,
8879 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
8880 0x68, 0x98, 0x4D, 0x04,
8881 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
8882 0xF8, 0x88, 0xFB, 0x23,
8883 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
8884 0x00, 0x33, 0x0A, 0x00,
8885 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
8886 0xC2, 0x88, 0xCD, 0x04,
8887 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
8888 0x06, 0xAB, 0x82, 0x01,
8889 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
8890 0x3C, 0x01, 0x00, 0x05,
8891 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
8892 0x15, 0x23, 0xA1, 0x01,
8893 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
8894 0x06, 0x61, 0x00, 0xA0,
8895 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
8896 0xC2, 0x88, 0x06, 0x23,
8897 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
8898 0x57, 0x60, 0x00, 0xA0,
8899 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
8900 0x4B, 0x00, 0x06, 0x61,
8901 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
8902 0x4F, 0x00, 0x84, 0x97,
8903 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
8904 0x48, 0x04, 0x84, 0x80,
8905 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
8906 0x81, 0x73, 0x06, 0x29,
8907 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
8908 0x04, 0x98, 0xF0, 0x80,
8909 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
8910 0x34, 0x02, 0x03, 0xA6,
8911 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
8912 0x46, 0x82, 0xFE, 0x95,
8913 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
8914 0x07, 0xA6, 0x5A, 0x02,
8915 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
8916 0x48, 0x82, 0x60, 0x96,
8917 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
8918 0x04, 0x01, 0x0C, 0xDC,
8919 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
8920 0x6F, 0x00, 0xA5, 0x01,
8921 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
8922 0x02, 0xA6, 0xAA, 0x02,
8923 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
8924 0x01, 0xA6, 0xB4, 0x02,
8925 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
8926 0x80, 0x63, 0x00, 0x43,
8927 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
8928 0x04, 0x61, 0x84, 0x01,
8929 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
8930 0x00, 0x00, 0xEA, 0x82,
8931 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
8932 0x00, 0x33, 0x1F, 0x00,
8933 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
8934 0xB6, 0x2D, 0x01, 0xA6,
8935 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
8936 0x10, 0x03, 0x03, 0xA6,
8937 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
8938 0x7C, 0x95, 0xEE, 0x82,
8939 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
8940 0x04, 0x01, 0x2D, 0xC8,
8941 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
8942 0x05, 0x05, 0x86, 0x98,
8943 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
8944 0x3C, 0x04, 0x06, 0xA6,
8945 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
8946 0x7C, 0x95, 0x32, 0x83,
8947 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
8948 0xEB, 0x04, 0x00, 0x33,
8949 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
8950 0xFF, 0xA2, 0x7A, 0x03,
8951 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
8952 0x00, 0xA2, 0x9A, 0x03,
8953 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
8954 0x01, 0xA6, 0x96, 0x03,
8955 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
8956 0xA4, 0x03, 0x00, 0xA6,
8957 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
8958 0x07, 0xA6, 0xB2, 0x03,
8959 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
8960 0xA8, 0x98, 0x80, 0x42,
8961 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
8962 0xC0, 0x83, 0x00, 0x33,
8963 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
8964 0xA0, 0x01, 0x12, 0x23,
8965 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
8966 0x80, 0x67, 0x05, 0x23,
8967 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
8968 0x06, 0xA6, 0x0A, 0x04,
8969 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
8970 0xF4, 0x83, 0x20, 0x84,
8971 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
8972 0x83, 0x03, 0x80, 0x63,
8973 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
8974 0x38, 0x04, 0x00, 0x33,
8975 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
8976 0x1D, 0x01, 0x06, 0xCC,
8977 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
8978 0xA2, 0x0D, 0x80, 0x63,
8979 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
8980 0x80, 0x63, 0xA3, 0x01,
8981 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
8982 0x76, 0x04, 0xE0, 0x00,
8983 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
8984 0x00, 0x33, 0x1E, 0x00,
8985 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
8986 0x08, 0x23, 0x22, 0xA3,
8987 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
8988 0xC4, 0x04, 0x42, 0x23,
8989 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
8990 0xF8, 0x88, 0x04, 0x98,
8991 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
8992 0x81, 0x62, 0xE8, 0x81,
8993 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
8994 0x00, 0x33, 0x00, 0x81,
8995 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
8996 0xF8, 0x88, 0x04, 0x23,
8997 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
8998 0xF4, 0x04, 0x00, 0x33,
8999 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9000 0x04, 0x23, 0xA0, 0x01,
9001 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9002 0x00, 0xA3, 0x22, 0x05,
9003 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9004 0x46, 0x97, 0xCD, 0x04,
9005 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9006 0x82, 0x01, 0x34, 0x85,
9007 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9008 0x1D, 0x01, 0x04, 0xD6,
9009 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9010 0x49, 0x00, 0x81, 0x01,
9011 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9012 0x49, 0x04, 0x80, 0x01,
9013 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9014 0x01, 0x23, 0xEA, 0x00,
9015 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9016 0x07, 0xA4, 0xF8, 0x05,
9017 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9018 0xC2, 0x88, 0x04, 0xA0,
9019 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9020 0x00, 0xA2, 0xA4, 0x05,
9021 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9022 0x62, 0x97, 0x04, 0x85,
9023 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9024 0xF4, 0x85, 0x03, 0xA0,
9025 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9026 0xCC, 0x86, 0x07, 0xA0,
9027 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9028 0x80, 0x67, 0x80, 0x63,
9029 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9030 0xF8, 0x88, 0x07, 0x23,
9031 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9032 0x00, 0x63, 0x4A, 0x00,
9033 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9034 0x07, 0x41, 0x83, 0x03,
9035 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9036 0x1D, 0x01, 0x01, 0xD6,
9037 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9038 0x07, 0xA6, 0x7C, 0x05,
9039 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9040 0x52, 0x00, 0x06, 0x61,
9041 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9042 0x00, 0x63, 0x1D, 0x01,
9043 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9044 0x07, 0x41, 0x00, 0x63,
9045 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9046 0xDF, 0x00, 0x06, 0xA6,
9047 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9048 0x00, 0x40, 0xC0, 0x20,
9049 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9050 0x06, 0xA6, 0x94, 0x06,
9051 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9052 0x40, 0x0E, 0x80, 0x63,
9053 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9054 0x80, 0x63, 0x00, 0x43,
9055 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9056 0x80, 0x67, 0x40, 0x0E,
9057 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9058 0x07, 0xA6, 0xD6, 0x06,
9059 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9060 0x0A, 0x2B, 0x07, 0xA6,
9061 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9062 0xF4, 0x06, 0xC0, 0x0E,
9063 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9064 0x81, 0x62, 0x04, 0x01,
9065 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9066 0x8C, 0x06, 0x00, 0x33,
9067 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9068 0x80, 0x63, 0x06, 0xA6,
9069 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9070 0x00, 0x00, 0x80, 0x67,
9071 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9072 0xBF, 0x23, 0x04, 0x61,
9073 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9074 0x00, 0x01, 0xF2, 0x00,
9075 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9076 0x80, 0x05, 0x81, 0x05,
9077 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9078 0x70, 0x00, 0x81, 0x01,
9079 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9080 0x70, 0x00, 0x80, 0x01,
9081 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9082 0xF1, 0x00, 0x70, 0x00,
9083 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9084 0x71, 0x04, 0x70, 0x00,
9085 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9086 0xA3, 0x01, 0xA2, 0x01,
9087 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9088 0xC4, 0x07, 0x00, 0x33,
9089 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9090 0x48, 0x00, 0xB0, 0x01,
9091 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9092 0x00, 0xA2, 0xE4, 0x07,
9093 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9094 0x05, 0x05, 0x00, 0x63,
9095 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9096 0x76, 0x08, 0x80, 0x02,
9097 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9098 0x00, 0x02, 0x00, 0xA0,
9099 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9100 0x00, 0x63, 0xF3, 0x04,
9101 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9102 0x00, 0xA2, 0x44, 0x08,
9103 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9104 0x24, 0x08, 0x04, 0x98,
9105 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9106 0x5A, 0x88, 0x02, 0x01,
9107 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9108 0x00, 0xA3, 0x64, 0x08,
9109 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9110 0x06, 0xA6, 0x76, 0x08,
9111 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9112 0x00, 0x63, 0x38, 0x2B,
9113 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9114 0x05, 0x05, 0xB2, 0x09,
9115 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9116 0x80, 0x32, 0x80, 0x36,
9117 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9118 0x40, 0x36, 0x40, 0x3A,
9119 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9120 0x5D, 0x00, 0xFE, 0xC3,
9121 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9122 0xFF, 0xFD, 0x80, 0x73,
9123 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9124 0xA1, 0x23, 0xA1, 0x01,
9125 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9126 0x80, 0x00, 0x03, 0xC2,
9127 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9128 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009129};
9130
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009131static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9132static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009133
9134#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009135static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9136 INQUIRY,
9137 REQUEST_SENSE,
9138 READ_CAPACITY,
9139 READ_TOC,
9140 MODE_SELECT,
9141 MODE_SENSE,
9142 MODE_SELECT_10,
9143 MODE_SENSE_10,
9144 0xFF,
9145 0xFF,
9146 0xFF,
9147 0xFF,
9148 0xFF,
9149 0xFF,
9150 0xFF,
9151 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009152};
9153
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009154static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009155{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009156 PortAddr iop_base;
9157 ulong last_int_level;
9158 int sta;
9159 int n_q_required;
9160 int disable_syn_offset_one_fix;
9161 int i;
9162 ASC_PADDR addr;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009163 ushort sg_entry_cnt = 0;
9164 ushort sg_entry_cnt_minus_one = 0;
9165 uchar target_ix;
9166 uchar tid_no;
9167 uchar sdtr_data;
9168 uchar extra_bytes;
9169 uchar scsi_cmd;
9170 uchar disable_cmd;
9171 ASC_SG_HEAD *sg_head;
9172 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009173
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009174 iop_base = asc_dvc->iop_base;
9175 sg_head = scsiq->sg_head;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009176 if (asc_dvc->err_code != 0)
9177 return (ERR);
9178 if (scsiq == (ASC_SCSI_Q *)0L) {
9179 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9180 return (ERR);
9181 }
9182 scsiq->q1.q_no = 0;
9183 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9184 scsiq->q1.extra_bytes = 0;
9185 }
9186 sta = 0;
9187 target_ix = scsiq->q2.target_ix;
9188 tid_no = ASC_TIX_TO_TID(target_ix);
9189 n_q_required = 1;
9190 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9191 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9192 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9193 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9194 AscMsgOutSDTR(asc_dvc,
9195 asc_dvc->
9196 sdtr_period_tbl[(sdtr_data >> 4) &
9197 (uchar)(asc_dvc->
9198 max_sdtr_index -
9199 1)],
9200 (uchar)(sdtr_data & (uchar)
9201 ASC_SYN_MAX_OFFSET));
9202 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9203 }
9204 }
9205 last_int_level = DvcEnterCritical();
9206 if (asc_dvc->in_critical_cnt != 0) {
9207 DvcLeaveCritical(last_int_level);
9208 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9209 return (ERR);
9210 }
9211 asc_dvc->in_critical_cnt++;
9212 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9213 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9214 asc_dvc->in_critical_cnt--;
9215 DvcLeaveCritical(last_int_level);
9216 return (ERR);
9217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009218#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009219 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9220 asc_dvc->in_critical_cnt--;
9221 DvcLeaveCritical(last_int_level);
9222 return (ERR);
9223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009224#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009225 if (sg_entry_cnt == 1) {
9226 scsiq->q1.data_addr =
9227 (ADV_PADDR)sg_head->sg_list[0].addr;
9228 scsiq->q1.data_cnt =
9229 (ADV_DCNT)sg_head->sg_list[0].bytes;
9230 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9231 }
9232 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9233 }
9234 scsi_cmd = scsiq->cdbptr[0];
9235 disable_syn_offset_one_fix = FALSE;
9236 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9237 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9238 if (scsiq->q1.cntl & QC_SG_HEAD) {
9239 data_cnt = 0;
9240 for (i = 0; i < sg_entry_cnt; i++) {
9241 data_cnt +=
9242 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9243 bytes);
9244 }
9245 } else {
9246 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9247 }
9248 if (data_cnt != 0UL) {
9249 if (data_cnt < 512UL) {
9250 disable_syn_offset_one_fix = TRUE;
9251 } else {
9252 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9253 i++) {
9254 disable_cmd =
9255 _syn_offset_one_disable_cmd[i];
9256 if (disable_cmd == 0xFF) {
9257 break;
9258 }
9259 if (scsi_cmd == disable_cmd) {
9260 disable_syn_offset_one_fix =
9261 TRUE;
9262 break;
9263 }
9264 }
9265 }
9266 }
9267 }
9268 if (disable_syn_offset_one_fix) {
9269 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9270 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9271 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9272 } else {
9273 scsiq->q2.tag_code &= 0x27;
9274 }
9275 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9276 if (asc_dvc->bug_fix_cntl) {
9277 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9278 if ((scsi_cmd == READ_6) ||
9279 (scsi_cmd == READ_10)) {
9280 addr =
9281 (ADV_PADDR)le32_to_cpu(sg_head->
9282 sg_list
9283 [sg_entry_cnt_minus_one].
9284 addr) +
9285 (ADV_DCNT)le32_to_cpu(sg_head->
9286 sg_list
9287 [sg_entry_cnt_minus_one].
9288 bytes);
9289 extra_bytes =
9290 (uchar)((ushort)addr & 0x0003);
9291 if ((extra_bytes != 0)
9292 &&
9293 ((scsiq->q2.
9294 tag_code &
9295 ASC_TAG_FLAG_EXTRA_BYTES)
9296 == 0)) {
9297 scsiq->q2.tag_code |=
9298 ASC_TAG_FLAG_EXTRA_BYTES;
9299 scsiq->q1.extra_bytes =
9300 extra_bytes;
9301 data_cnt =
9302 le32_to_cpu(sg_head->
9303 sg_list
9304 [sg_entry_cnt_minus_one].
9305 bytes);
9306 data_cnt -=
9307 (ASC_DCNT) extra_bytes;
9308 sg_head->
9309 sg_list
9310 [sg_entry_cnt_minus_one].
9311 bytes =
9312 cpu_to_le32(data_cnt);
9313 }
9314 }
9315 }
9316 }
9317 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009318#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009319 /*
9320 * Set the sg_entry_cnt to the maximum possible. The rest of
9321 * the SG elements will be copied when the RISC completes the
9322 * SG elements that fit and halts.
9323 */
9324 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9325 sg_entry_cnt = ASC_MAX_SG_LIST;
9326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009327#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009328 n_q_required = AscSgListToQueue(sg_entry_cnt);
9329 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9330 (uint) n_q_required)
9331 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9332 if ((sta =
9333 AscSendScsiQueue(asc_dvc, scsiq,
9334 n_q_required)) == 1) {
9335 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009336 DvcLeaveCritical(last_int_level);
9337 return (sta);
9338 }
9339 }
9340 } else {
9341 if (asc_dvc->bug_fix_cntl) {
9342 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9343 if ((scsi_cmd == READ_6) ||
9344 (scsi_cmd == READ_10)) {
9345 addr =
9346 le32_to_cpu(scsiq->q1.data_addr) +
9347 le32_to_cpu(scsiq->q1.data_cnt);
9348 extra_bytes =
9349 (uchar)((ushort)addr & 0x0003);
9350 if ((extra_bytes != 0)
9351 &&
9352 ((scsiq->q2.
9353 tag_code &
9354 ASC_TAG_FLAG_EXTRA_BYTES)
9355 == 0)) {
9356 data_cnt =
9357 le32_to_cpu(scsiq->q1.
9358 data_cnt);
9359 if (((ushort)data_cnt & 0x01FF)
9360 == 0) {
9361 scsiq->q2.tag_code |=
9362 ASC_TAG_FLAG_EXTRA_BYTES;
9363 data_cnt -= (ASC_DCNT)
9364 extra_bytes;
9365 scsiq->q1.data_cnt =
9366 cpu_to_le32
9367 (data_cnt);
9368 scsiq->q1.extra_bytes =
9369 extra_bytes;
9370 }
9371 }
9372 }
9373 }
9374 }
9375 n_q_required = 1;
9376 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9377 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9378 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9379 n_q_required)) == 1) {
9380 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009381 DvcLeaveCritical(last_int_level);
9382 return (sta);
9383 }
9384 }
9385 }
9386 asc_dvc->in_critical_cnt--;
9387 DvcLeaveCritical(last_int_level);
9388 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009389}
9390
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009391static int
9392AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009393{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009394 PortAddr iop_base;
9395 uchar free_q_head;
9396 uchar next_qp;
9397 uchar tid_no;
9398 uchar target_ix;
9399 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009400
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009401 iop_base = asc_dvc->iop_base;
9402 target_ix = scsiq->q2.target_ix;
9403 tid_no = ASC_TIX_TO_TID(target_ix);
9404 sta = 0;
9405 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9406 if (n_q_required > 1) {
9407 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9408 free_q_head, (uchar)
9409 (n_q_required)))
9410 != (uchar)ASC_QLINK_END) {
9411 asc_dvc->last_q_shortage = 0;
9412 scsiq->sg_head->queue_cnt = n_q_required - 1;
9413 scsiq->q1.q_no = free_q_head;
9414 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9415 free_q_head)) == 1) {
9416 AscPutVarFreeQHead(iop_base, next_qp);
9417 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9418 asc_dvc->cur_dvc_qng[tid_no]++;
9419 }
9420 return (sta);
9421 }
9422 } else if (n_q_required == 1) {
9423 if ((next_qp = AscAllocFreeQueue(iop_base,
9424 free_q_head)) !=
9425 ASC_QLINK_END) {
9426 scsiq->q1.q_no = free_q_head;
9427 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9428 free_q_head)) == 1) {
9429 AscPutVarFreeQHead(iop_base, next_qp);
9430 asc_dvc->cur_total_qng++;
9431 asc_dvc->cur_dvc_qng[tid_no]++;
9432 }
9433 return (sta);
9434 }
9435 }
9436 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009437}
9438
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009439static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009440{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009441 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009443 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9444 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9445 n_sg_list_qs++;
9446 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009447}
9448
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009449static uint
9450AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009451{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009452 uint cur_used_qs;
9453 uint cur_free_qs;
9454 ASC_SCSI_BIT_ID_TYPE target_id;
9455 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009457 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9458 tid_no = ASC_TIX_TO_TID(target_ix);
9459 if ((asc_dvc->unit_not_ready & target_id) ||
9460 (asc_dvc->queue_full_or_busy & target_id)) {
9461 return (0);
9462 }
9463 if (n_qs == 1) {
9464 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9465 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9466 } else {
9467 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9468 (uint) ASC_MIN_FREE_Q;
9469 }
9470 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9471 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9472 if (asc_dvc->cur_dvc_qng[tid_no] >=
9473 asc_dvc->max_dvc_qng[tid_no]) {
9474 return (0);
9475 }
9476 return (cur_free_qs);
9477 }
9478 if (n_qs > 1) {
9479 if ((n_qs > asc_dvc->last_q_shortage)
9480 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9481 asc_dvc->last_q_shortage = n_qs;
9482 }
9483 }
9484 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009485}
9486
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009487static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009488{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009489 ushort q_addr;
9490 uchar tid_no;
9491 uchar sdtr_data;
9492 uchar syn_period_ix;
9493 uchar syn_offset;
9494 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009495
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009496 iop_base = asc_dvc->iop_base;
9497 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9498 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9499 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9500 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9501 syn_period_ix =
9502 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9503 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9504 AscMsgOutSDTR(asc_dvc,
9505 asc_dvc->sdtr_period_tbl[syn_period_ix],
9506 syn_offset);
9507 scsiq->q1.cntl |= QC_MSG_OUT;
9508 }
9509 q_addr = ASC_QNO_TO_QADDR(q_no);
9510 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9511 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9512 }
9513 scsiq->q1.status = QS_FREE;
9514 AscMemWordCopyPtrToLram(iop_base,
9515 q_addr + ASC_SCSIQ_CDB_BEG,
9516 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009517
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009518 DvcPutScsiQ(iop_base,
9519 q_addr + ASC_SCSIQ_CPY_BEG,
9520 (uchar *)&scsiq->q1.cntl,
9521 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9522 AscWriteLramWord(iop_base,
9523 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9524 (ushort)(((ushort)scsiq->q1.
9525 q_no << 8) | (ushort)QS_READY));
9526 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009527}
9528
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009529static int
9530AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009531{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009532 int sta;
9533 int i;
9534 ASC_SG_HEAD *sg_head;
9535 ASC_SG_LIST_Q scsi_sg_q;
9536 ASC_DCNT saved_data_addr;
9537 ASC_DCNT saved_data_cnt;
9538 PortAddr iop_base;
9539 ushort sg_list_dwords;
9540 ushort sg_index;
9541 ushort sg_entry_cnt;
9542 ushort q_addr;
9543 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009544
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009545 iop_base = asc_dvc->iop_base;
9546 sg_head = scsiq->sg_head;
9547 saved_data_addr = scsiq->q1.data_addr;
9548 saved_data_cnt = scsiq->q1.data_cnt;
9549 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9550 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009551#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009552 /*
9553 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9554 * then not all SG elements will fit in the allocated queues.
9555 * The rest of the SG elements will be copied when the RISC
9556 * completes the SG elements that fit and halts.
9557 */
9558 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9559 /*
9560 * Set sg_entry_cnt to be the number of SG elements that
9561 * will fit in the allocated SG queues. It is minus 1, because
9562 * the first SG element is handled above. ASC_MAX_SG_LIST is
9563 * already inflated by 1 to account for this. For example it
9564 * may be 50 which is 1 + 7 queues * 7 SG elements.
9565 */
9566 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009567
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009568 /*
9569 * Keep track of remaining number of SG elements that will
9570 * need to be handled from a_isr.c.
9571 */
9572 scsiq->remain_sg_entry_cnt =
9573 sg_head->entry_cnt - ASC_MAX_SG_LIST;
9574 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009575#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009576 /*
9577 * Set sg_entry_cnt to be the number of SG elements that
9578 * will fit in the allocated SG queues. It is minus 1, because
9579 * the first SG element is handled above.
9580 */
9581 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009582#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009584#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009585 if (sg_entry_cnt != 0) {
9586 scsiq->q1.cntl |= QC_SG_HEAD;
9587 q_addr = ASC_QNO_TO_QADDR(q_no);
9588 sg_index = 1;
9589 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
9590 scsi_sg_q.sg_head_qp = q_no;
9591 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
9592 for (i = 0; i < sg_head->queue_cnt; i++) {
9593 scsi_sg_q.seq_no = i + 1;
9594 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
9595 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
9596 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
9597 if (i == 0) {
9598 scsi_sg_q.sg_list_cnt =
9599 ASC_SG_LIST_PER_Q;
9600 scsi_sg_q.sg_cur_list_cnt =
9601 ASC_SG_LIST_PER_Q;
9602 } else {
9603 scsi_sg_q.sg_list_cnt =
9604 ASC_SG_LIST_PER_Q - 1;
9605 scsi_sg_q.sg_cur_list_cnt =
9606 ASC_SG_LIST_PER_Q - 1;
9607 }
9608 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009609#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009610 /*
9611 * This is the last SG queue in the list of
9612 * allocated SG queues. If there are more
9613 * SG elements than will fit in the allocated
9614 * queues, then set the QCSG_SG_XFER_MORE flag.
9615 */
9616 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9617 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
9618 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009619#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009620 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009621#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009623#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009624 sg_list_dwords = sg_entry_cnt << 1;
9625 if (i == 0) {
9626 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
9627 scsi_sg_q.sg_cur_list_cnt =
9628 sg_entry_cnt;
9629 } else {
9630 scsi_sg_q.sg_list_cnt =
9631 sg_entry_cnt - 1;
9632 scsi_sg_q.sg_cur_list_cnt =
9633 sg_entry_cnt - 1;
9634 }
9635 sg_entry_cnt = 0;
9636 }
9637 next_qp = AscReadLramByte(iop_base,
9638 (ushort)(q_addr +
9639 ASC_SCSIQ_B_FWD));
9640 scsi_sg_q.q_no = next_qp;
9641 q_addr = ASC_QNO_TO_QADDR(next_qp);
9642 AscMemWordCopyPtrToLram(iop_base,
9643 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
9644 (uchar *)&scsi_sg_q,
9645 sizeof(ASC_SG_LIST_Q) >> 1);
9646 AscMemDWordCopyPtrToLram(iop_base,
9647 q_addr + ASC_SGQ_LIST_BEG,
9648 (uchar *)&sg_head->
9649 sg_list[sg_index],
9650 sg_list_dwords);
9651 sg_index += ASC_SG_LIST_PER_Q;
9652 scsiq->next_sg_index = sg_index;
9653 }
9654 } else {
9655 scsiq->q1.cntl &= ~QC_SG_HEAD;
9656 }
9657 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
9658 scsiq->q1.data_addr = saved_data_addr;
9659 scsiq->q1.data_cnt = saved_data_cnt;
9660 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009661}
9662
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009663static int
9664AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009665{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009666 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009668 if (AscHostReqRiscHalt(iop_base)) {
9669 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9670 AscStartChip(iop_base);
9671 return (sta);
9672 }
9673 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009674}
9675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009676static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009677{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009678 ASC_SCSI_BIT_ID_TYPE org_id;
9679 int i;
9680 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009682 AscSetBank(iop_base, 1);
9683 org_id = AscReadChipDvcID(iop_base);
9684 for (i = 0; i <= ASC_MAX_TID; i++) {
9685 if (org_id == (0x01 << i))
9686 break;
9687 }
9688 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
9689 AscWriteChipDvcID(iop_base, id);
9690 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
9691 AscSetBank(iop_base, 0);
9692 AscSetChipSyn(iop_base, sdtr_data);
9693 if (AscGetChipSyn(iop_base) != sdtr_data) {
9694 sta = FALSE;
9695 }
9696 } else {
9697 sta = FALSE;
9698 }
9699 AscSetBank(iop_base, 1);
9700 AscWriteChipDvcID(iop_base, org_id);
9701 AscSetBank(iop_base, 0);
9702 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009703}
9704
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009705static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009706{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009707 uchar i;
9708 ushort s_addr;
9709 PortAddr iop_base;
9710 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009711
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009712 iop_base = asc_dvc->iop_base;
9713 warn_code = 0;
9714 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
9715 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
9716 64) >> 1)
9717 );
9718 i = ASC_MIN_ACTIVE_QNO;
9719 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
9720 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9721 (uchar)(i + 1));
9722 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9723 (uchar)(asc_dvc->max_total_qng));
9724 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9725 (uchar)i);
9726 i++;
9727 s_addr += ASC_QBLK_SIZE;
9728 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
9729 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9730 (uchar)(i + 1));
9731 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9732 (uchar)(i - 1));
9733 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9734 (uchar)i);
9735 }
9736 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9737 (uchar)ASC_QLINK_END);
9738 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9739 (uchar)(asc_dvc->max_total_qng - 1));
9740 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9741 (uchar)asc_dvc->max_total_qng);
9742 i++;
9743 s_addr += ASC_QBLK_SIZE;
9744 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
9745 i++, s_addr += ASC_QBLK_SIZE) {
9746 AscWriteLramByte(iop_base,
9747 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
9748 AscWriteLramByte(iop_base,
9749 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
9750 AscWriteLramByte(iop_base,
9751 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
9752 }
9753 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009754}
9755
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009756static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009757{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009758 PortAddr iop_base;
9759 int i;
9760 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009762 iop_base = asc_dvc->iop_base;
9763 AscPutRiscVarFreeQHead(iop_base, 1);
9764 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9765 AscPutVarFreeQHead(iop_base, 1);
9766 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9767 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
9768 (uchar)((int)asc_dvc->max_total_qng + 1));
9769 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
9770 (uchar)((int)asc_dvc->max_total_qng + 2));
9771 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
9772 asc_dvc->max_total_qng);
9773 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
9774 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
9775 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
9776 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
9777 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
9778 AscPutQDoneInProgress(iop_base, 0);
9779 lram_addr = ASC_QADR_BEG;
9780 for (i = 0; i < 32; i++, lram_addr += 2) {
9781 AscWriteLramWord(iop_base, lram_addr, 0);
9782 }
9783 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009784}
9785
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009786static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009787{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009788 if (asc_dvc->err_code == 0) {
9789 asc_dvc->err_code = err_code;
9790 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
9791 err_code);
9792 }
9793 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009794}
9795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009796static uchar
9797AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009798{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009799 EXT_MSG sdtr_buf;
9800 uchar sdtr_period_index;
9801 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009803 iop_base = asc_dvc->iop_base;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009804 sdtr_buf.msg_type = EXTENDED_MESSAGE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009805 sdtr_buf.msg_len = MS_SDTR_LEN;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009806 sdtr_buf.msg_req = EXTENDED_SDTR;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009807 sdtr_buf.xfer_period = sdtr_period;
9808 sdtr_offset &= ASC_SYN_MAX_OFFSET;
9809 sdtr_buf.req_ack_offset = sdtr_offset;
9810 if ((sdtr_period_index =
9811 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
9812 asc_dvc->max_sdtr_index) {
9813 AscMemWordCopyPtrToLram(iop_base,
9814 ASCV_MSGOUT_BEG,
9815 (uchar *)&sdtr_buf,
9816 sizeof(EXT_MSG) >> 1);
9817 return ((sdtr_period_index << 4) | sdtr_offset);
9818 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009819
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009820 sdtr_buf.req_ack_offset = 0;
9821 AscMemWordCopyPtrToLram(iop_base,
9822 ASCV_MSGOUT_BEG,
9823 (uchar *)&sdtr_buf,
9824 sizeof(EXT_MSG) >> 1);
9825 return (0);
9826 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009827}
9828
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009829static uchar
9830AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009831{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009832 uchar byte;
9833 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009834
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009835 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
9836 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
9837 ) {
9838 return (0xFF);
9839 }
9840 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
9841 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009842}
9843
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009844static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009845{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009846 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9847 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
9848 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009849}
9850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009851static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009852{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009853 uchar *period_table;
9854 int max_index;
9855 int min_index;
9856 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009858 period_table = asc_dvc->sdtr_period_tbl;
9859 max_index = (int)asc_dvc->max_sdtr_index;
9860 min_index = (int)asc_dvc->host_init_sdtr_index;
9861 if ((syn_time <= period_table[max_index])) {
9862 for (i = min_index; i < (max_index - 1); i++) {
9863 if (syn_time <= period_table[i]) {
9864 return ((uchar)i);
9865 }
9866 }
9867 return ((uchar)max_index);
9868 } else {
9869 return ((uchar)(max_index + 1));
9870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009871}
9872
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009873static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009874{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009875 ushort q_addr;
9876 uchar next_qp;
9877 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009878
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009879 q_addr = ASC_QNO_TO_QADDR(free_q_head);
9880 q_status = (uchar)AscReadLramByte(iop_base,
9881 (ushort)(q_addr +
9882 ASC_SCSIQ_B_STATUS));
9883 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
9884 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
9885 return (next_qp);
9886 }
9887 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009888}
9889
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009890static uchar
9891AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009892{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009893 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009894
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009895 for (i = 0; i < n_free_q; i++) {
9896 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
9897 == ASC_QLINK_END) {
9898 return (ASC_QLINK_END);
9899 }
9900 }
9901 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009902}
9903
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009904static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009905{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009906 int count = 0;
9907 int sta = 0;
9908 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009909
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009910 if (AscIsChipHalted(iop_base))
9911 return (1);
9912 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
9913 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9914 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
9915 do {
9916 if (AscIsChipHalted(iop_base)) {
9917 sta = 1;
9918 break;
9919 }
9920 DvcSleepMilliSecond(100);
9921 } while (count++ < 20);
9922 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
9923 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009924}
9925
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009926static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009927{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009928 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009930 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
9931 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9932 ASC_STOP_REQ_RISC_STOP);
9933 do {
9934 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
9935 ASC_STOP_ACK_RISC_STOP) {
9936 return (1);
9937 }
9938 DvcSleepMilliSecond(100);
9939 } while (count++ < 20);
9940 }
9941 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009942}
9943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009944static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009945{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009946 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009947}
9948
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009949static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009950{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009951 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009952}
9953
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009954static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009955{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009956 AscSetChipControl(iop_base, 0);
9957 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
9958 return (0);
9959 }
9960 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009961}
9962
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009963static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009964{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009965 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009966
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009967 cc_val =
9968 AscGetChipControl(iop_base) &
9969 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
9970 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
9971 AscSetChipIH(iop_base, INS_HALT);
9972 AscSetChipIH(iop_base, INS_RFLAG_WTM);
9973 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
9974 return (0);
9975 }
9976 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009977}
9978
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009979static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009980{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009981 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
9982 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
9983 return (1);
9984 }
9985 }
9986 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009987}
9988
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009989static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009990{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009991 AscSetBank(iop_base, 1);
9992 AscWriteChipIH(iop_base, ins_code);
9993 AscSetBank(iop_base, 0);
9994 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009995}
9996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009997static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009998{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009999 uchar host_flag;
10000 uchar risc_flag;
10001 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010002
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010003 loop = 0;
10004 do {
10005 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10006 if (loop++ > 0x7FFF) {
10007 break;
10008 }
10009 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10010 host_flag =
10011 AscReadLramByte(iop_base,
10012 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10013 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10014 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10015 AscSetChipStatus(iop_base, CIW_INT_ACK);
10016 loop = 0;
10017 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10018 AscSetChipStatus(iop_base, CIW_INT_ACK);
10019 if (loop++ > 3) {
10020 break;
10021 }
10022 }
10023 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10024 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010025}
10026
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010027static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010028{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010029 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010031 cfg = AscGetChipCfgLsw(iop_base);
10032 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10033 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010034}
10035
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010036static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010037{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010038 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010039
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010040 cfg = AscGetChipCfgLsw(iop_base);
10041 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10042 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010043}
10044
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010045static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010046{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010047 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010048
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010049 val = AscGetChipControl(iop_base) &
10050 (~
10051 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10052 CC_CHIP_RESET));
10053 if (bank == 1) {
10054 val |= CC_BANK_ONE;
10055 } else if (bank == 2) {
10056 val |= CC_DIAG | CC_BANK_ONE;
10057 } else {
10058 val &= ~CC_BANK_ONE;
10059 }
10060 AscSetChipControl(iop_base, val);
10061 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010062}
10063
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010064static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010065{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010066 PortAddr iop_base;
10067 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010068
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010069 iop_base = asc_dvc->iop_base;
10070 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10071 && (i-- > 0)) {
10072 DvcSleepMilliSecond(100);
10073 }
10074 AscStopChip(iop_base);
10075 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10076 DvcDelayNanoSecond(asc_dvc, 60000);
10077 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10078 AscSetChipIH(iop_base, INS_HALT);
10079 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10080 AscSetChipControl(iop_base, CC_HALT);
10081 DvcSleepMilliSecond(200);
10082 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10083 AscSetChipStatus(iop_base, 0);
10084 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010085}
10086
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010087static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010088{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010089 if (bus_type & ASC_IS_ISA)
10090 return (ASC_MAX_ISA_DMA_COUNT);
10091 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10092 return (ASC_MAX_VL_DMA_COUNT);
10093 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010094}
10095
10096#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010097static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010098{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010099 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010100
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010101 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10102 if (channel == 0x03)
10103 return (0);
10104 else if (channel == 0x00)
10105 return (7);
10106 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010107}
10108
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010109static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010110{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010111 ushort cfg_lsw;
10112 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010113
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010114 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10115 if (dma_channel == 7)
10116 value = 0x00;
10117 else
10118 value = dma_channel - 4;
10119 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10120 cfg_lsw |= value;
10121 AscSetChipCfgLsw(iop_base, cfg_lsw);
10122 return (AscGetIsaDmaChannel(iop_base));
10123 }
10124 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010125}
10126
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010127static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010128{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010129 speed_value &= 0x07;
10130 AscSetBank(iop_base, 1);
10131 AscWriteChipDmaSpeed(iop_base, speed_value);
10132 AscSetBank(iop_base, 0);
10133 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010134}
10135
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010136static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010137{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010138 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010139
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010140 AscSetBank(iop_base, 1);
10141 speed_value = AscReadChipDmaSpeed(iop_base);
10142 speed_value &= 0x07;
10143 AscSetBank(iop_base, 0);
10144 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010145}
10146#endif /* CONFIG_ISA */
10147
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010148static ushort __devinit AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010149{
Matthew Wilcox9649af32007-07-26 21:51:47 -060010150 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010151
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010152 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -060010153 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010154 return (UW_ERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010155
Matthew Wilcox9649af32007-07-26 21:51:47 -060010156 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010157 warn_code |= AscInitAscDvcVar(asc_dvc);
10158 warn_code |= AscInitFromEEP(asc_dvc);
10159 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010160 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010161 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010162 } else {
10163 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10164 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010165 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010166}
10167
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010168static unsigned short __devinit
10169AscInitSetConfig(struct pci_dev *pdev, ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010170{
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010171 PortAddr iop_base = asc_dvc->iop_base;
10172 unsigned short cfg_msw;
10173 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010174
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010175 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10176 if (asc_dvc->err_code != 0)
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010177 return UW_ERR;
10178 if (!AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010179 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010180 return 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010182
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010183 cfg_msw = AscGetChipCfgMsw(iop_base);
10184 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10185 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10186 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10187 AscSetChipCfgMsw(iop_base, cfg_msw);
10188 }
10189 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10190 asc_dvc->cfg->cmd_qng_enabled) {
10191 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10192 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10193 }
10194 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10195 warn_code |= ASC_WARN_AUTO_CONFIG;
10196 }
10197 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10198 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10199 != asc_dvc->irq_no) {
10200 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10201 }
10202 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010203#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010204 if (asc_dvc->bus_type & ASC_IS_PCI) {
10205 cfg_msw &= 0xFFC0;
10206 AscSetChipCfgMsw(iop_base, cfg_msw);
10207 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10208 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010209 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
10210 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010211 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10212 asc_dvc->bug_fix_cntl |=
10213 ASC_BUG_FIX_ASYN_USE_SYN;
10214 }
10215 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010216 } else
10217#endif /* CONFIG_PCI */
10218 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010219 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10220 == ASC_CHIP_VER_ASYN_BUG) {
10221 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10222 }
10223 }
10224 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10225 asc_dvc->cfg->chip_scsi_id) {
10226 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010228#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010229 if (asc_dvc->bus_type & ASC_IS_ISA) {
10230 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10231 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010233#endif /* CONFIG_ISA */
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010234
10235 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10236 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010237}
10238
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010239static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010240{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010241 ushort warn_code;
10242 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010243
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010244 iop_base = asc_dvc->iop_base;
10245 warn_code = 0;
10246 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10247 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10248 AscResetChipAndScsiBus(asc_dvc);
10249 DvcSleepMilliSecond((ASC_DCNT)
10250 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10251 }
10252 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10253 if (asc_dvc->err_code != 0)
10254 return (UW_ERR);
10255 if (!AscFindSignature(asc_dvc->iop_base)) {
10256 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10257 return (warn_code);
10258 }
10259 AscDisableInterrupt(iop_base);
10260 warn_code |= AscInitLram(asc_dvc);
10261 if (asc_dvc->err_code != 0)
10262 return (UW_ERR);
10263 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10264 (ulong)_asc_mcode_chksum);
10265 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10266 _asc_mcode_size) != _asc_mcode_chksum) {
10267 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10268 return (warn_code);
10269 }
10270 warn_code |= AscInitMicroCodeVar(asc_dvc);
10271 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10272 AscEnableInterrupt(iop_base);
10273 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010274}
10275
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010276static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010277{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010278 int i;
10279 PortAddr iop_base;
10280 ushort warn_code;
10281 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010283 iop_base = asc_dvc->iop_base;
10284 warn_code = 0;
10285 asc_dvc->err_code = 0;
10286 if ((asc_dvc->bus_type &
10287 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10288 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10289 }
10290 AscSetChipControl(iop_base, CC_HALT);
10291 AscSetChipStatus(iop_base, 0);
10292 asc_dvc->bug_fix_cntl = 0;
10293 asc_dvc->pci_fix_asyn_xfer = 0;
10294 asc_dvc->pci_fix_asyn_xfer_always = 0;
10295 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10296 asc_dvc->sdtr_done = 0;
10297 asc_dvc->cur_total_qng = 0;
10298 asc_dvc->is_in_int = 0;
10299 asc_dvc->in_critical_cnt = 0;
10300 asc_dvc->last_q_shortage = 0;
10301 asc_dvc->use_tagged_qng = 0;
10302 asc_dvc->no_scam = 0;
10303 asc_dvc->unit_not_ready = 0;
10304 asc_dvc->queue_full_or_busy = 0;
10305 asc_dvc->redo_scam = 0;
10306 asc_dvc->res2 = 0;
10307 asc_dvc->host_init_sdtr_index = 0;
10308 asc_dvc->cfg->can_tagged_qng = 0;
10309 asc_dvc->cfg->cmd_qng_enabled = 0;
10310 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10311 asc_dvc->init_sdtr = 0;
10312 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10313 asc_dvc->scsi_reset_wait = 3;
10314 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10315 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10316 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10317 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10318 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10319 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10320 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10321 ASC_LIB_VERSION_MINOR;
10322 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10323 asc_dvc->cfg->chip_version = chip_version;
10324 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10325 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10326 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10327 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10328 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10329 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10330 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10331 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10332 asc_dvc->max_sdtr_index = 7;
10333 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10334 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10335 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10336 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10337 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10338 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10339 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10340 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10341 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10342 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10343 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10344 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10345 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10346 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10347 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10348 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10349 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10350 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10351 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10352 asc_dvc->max_sdtr_index = 15;
10353 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10354 AscSetExtraControl(iop_base,
10355 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10356 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10357 AscSetExtraControl(iop_base,
10358 (SEC_ACTIVE_NEGATE |
10359 SEC_ENABLE_FILTER));
10360 }
10361 }
10362 if (asc_dvc->bus_type == ASC_IS_PCI) {
10363 AscSetExtraControl(iop_base,
10364 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010366
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010367 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010368#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010369 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
Matthew Wilcox59fcf842007-07-26 11:54:15 -040010370 if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
10371 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10372 asc_dvc->bus_type = ASC_IS_ISAPNP;
10373 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010374 asc_dvc->cfg->isa_dma_channel =
10375 (uchar)AscGetIsaDmaChannel(iop_base);
10376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010377#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010378 for (i = 0; i <= ASC_MAX_TID; i++) {
10379 asc_dvc->cur_dvc_qng[i] = 0;
10380 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10381 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10382 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10383 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10384 }
10385 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010386}
10387
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010388static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010389{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010390 ASCEEP_CONFIG eep_config_buf;
10391 ASCEEP_CONFIG *eep_config;
10392 PortAddr iop_base;
10393 ushort chksum;
10394 ushort warn_code;
10395 ushort cfg_msw, cfg_lsw;
10396 int i;
10397 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010398
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010399 iop_base = asc_dvc->iop_base;
10400 warn_code = 0;
10401 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10402 AscStopQueueExe(iop_base);
10403 if ((AscStopChip(iop_base) == FALSE) ||
10404 (AscGetChipScsiCtrl(iop_base) != 0)) {
10405 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10406 AscResetChipAndScsiBus(asc_dvc);
10407 DvcSleepMilliSecond((ASC_DCNT)
10408 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10409 }
10410 if (AscIsChipHalted(iop_base) == FALSE) {
10411 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10412 return (warn_code);
10413 }
10414 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10415 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10416 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10417 return (warn_code);
10418 }
10419 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10420 cfg_msw = AscGetChipCfgMsw(iop_base);
10421 cfg_lsw = AscGetChipCfgLsw(iop_base);
10422 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10423 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10424 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10425 AscSetChipCfgMsw(iop_base, cfg_msw);
10426 }
10427 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
10428 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
10429 if (chksum == 0) {
10430 chksum = 0xaa55;
10431 }
10432 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10433 warn_code |= ASC_WARN_AUTO_CONFIG;
10434 if (asc_dvc->cfg->chip_version == 3) {
10435 if (eep_config->cfg_lsw != cfg_lsw) {
10436 warn_code |= ASC_WARN_EEPROM_RECOVER;
10437 eep_config->cfg_lsw =
10438 AscGetChipCfgLsw(iop_base);
10439 }
10440 if (eep_config->cfg_msw != cfg_msw) {
10441 warn_code |= ASC_WARN_EEPROM_RECOVER;
10442 eep_config->cfg_msw =
10443 AscGetChipCfgMsw(iop_base);
10444 }
10445 }
10446 }
10447 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
10448 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
10449 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
10450 eep_config->chksum);
10451 if (chksum != eep_config->chksum) {
10452 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
10453 ASC_CHIP_VER_PCI_ULTRA_3050) {
10454 ASC_DBG(1,
10455 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
10456 eep_config->init_sdtr = 0xFF;
10457 eep_config->disc_enable = 0xFF;
10458 eep_config->start_motor = 0xFF;
10459 eep_config->use_cmd_qng = 0;
10460 eep_config->max_total_qng = 0xF0;
10461 eep_config->max_tag_qng = 0x20;
10462 eep_config->cntl = 0xBFFF;
10463 ASC_EEP_SET_CHIP_ID(eep_config, 7);
10464 eep_config->no_scam = 0;
10465 eep_config->adapter_info[0] = 0;
10466 eep_config->adapter_info[1] = 0;
10467 eep_config->adapter_info[2] = 0;
10468 eep_config->adapter_info[3] = 0;
10469 eep_config->adapter_info[4] = 0;
10470 /* Indicate EEPROM-less board. */
10471 eep_config->adapter_info[5] = 0xBB;
10472 } else {
10473 ASC_PRINT
10474 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
10475 write_eep = 1;
10476 warn_code |= ASC_WARN_EEPROM_CHKSUM;
10477 }
10478 }
10479 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
10480 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
10481 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
10482 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
10483 asc_dvc->start_motor = eep_config->start_motor;
10484 asc_dvc->dvc_cntl = eep_config->cntl;
10485 asc_dvc->no_scam = eep_config->no_scam;
10486 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
10487 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
10488 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
10489 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
10490 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
10491 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
10492 if (!AscTestExternalLram(asc_dvc)) {
10493 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
10494 ASC_IS_PCI_ULTRA)) {
10495 eep_config->max_total_qng =
10496 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
10497 eep_config->max_tag_qng =
10498 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
10499 } else {
10500 eep_config->cfg_msw |= 0x0800;
10501 cfg_msw |= 0x0800;
10502 AscSetChipCfgMsw(iop_base, cfg_msw);
10503 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
10504 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
10505 }
10506 } else {
10507 }
10508 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
10509 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
10510 }
10511 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
10512 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
10513 }
10514 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
10515 eep_config->max_tag_qng = eep_config->max_total_qng;
10516 }
10517 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
10518 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
10519 }
10520 asc_dvc->max_total_qng = eep_config->max_total_qng;
10521 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
10522 eep_config->use_cmd_qng) {
10523 eep_config->disc_enable = eep_config->use_cmd_qng;
10524 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10525 }
10526 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
10527 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
10528 }
10529 ASC_EEP_SET_CHIP_ID(eep_config,
10530 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
10531 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
10532 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
10533 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
10534 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
10535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010536
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010537 for (i = 0; i <= ASC_MAX_TID; i++) {
10538 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
10539 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
10540 asc_dvc->cfg->sdtr_period_offset[i] =
10541 (uchar)(ASC_DEF_SDTR_OFFSET |
10542 (asc_dvc->host_init_sdtr_index << 4));
10543 }
10544 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
10545 if (write_eep) {
10546 if ((i =
10547 AscSetEEPConfig(iop_base, eep_config,
10548 asc_dvc->bus_type)) != 0) {
10549 ASC_PRINT1
10550 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
10551 i);
10552 } else {
10553 ASC_PRINT
10554 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
10555 }
10556 }
10557 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010558}
10559
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010560static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010561{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010562 int i;
10563 ushort warn_code;
10564 PortAddr iop_base;
10565 ASC_PADDR phy_addr;
10566 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010567
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010568 iop_base = asc_dvc->iop_base;
10569 warn_code = 0;
10570 for (i = 0; i <= ASC_MAX_TID; i++) {
10571 AscPutMCodeInitSDTRAtID(iop_base, i,
10572 asc_dvc->cfg->sdtr_period_offset[i]
10573 );
10574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010575
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010576 AscInitQLinkVar(asc_dvc);
10577 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
10578 asc_dvc->cfg->disc_enable);
10579 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
10580 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010581
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010582 /* Align overrun buffer on an 8 byte boundary. */
10583 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
10584 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
10585 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
10586 (uchar *)&phy_addr, 1);
10587 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
10588 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
10589 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010590
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010591 asc_dvc->cfg->mcode_date =
10592 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
10593 asc_dvc->cfg->mcode_version =
10594 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010595
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010596 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10597 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10598 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10599 return (warn_code);
10600 }
10601 if (AscStartChip(iop_base) != 1) {
10602 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10603 return (warn_code);
10604 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010605
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010606 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010607}
10608
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010609static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010610{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010611 PortAddr iop_base;
10612 ushort q_addr;
10613 ushort saved_word;
10614 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010615
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010616 iop_base = asc_dvc->iop_base;
10617 sta = 0;
10618 q_addr = ASC_QNO_TO_QADDR(241);
10619 saved_word = AscReadLramWord(iop_base, q_addr);
10620 AscSetChipLramAddr(iop_base, q_addr);
10621 AscSetChipLramData(iop_base, 0x55AA);
10622 DvcSleepMilliSecond(10);
10623 AscSetChipLramAddr(iop_base, q_addr);
10624 if (AscGetChipLramData(iop_base) == 0x55AA) {
10625 sta = 1;
10626 AscWriteLramWord(iop_base, q_addr, saved_word);
10627 }
10628 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010629}
10630
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010631static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010632{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010633 uchar read_back;
10634 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010635
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010636 retry = 0;
10637 while (TRUE) {
10638 AscSetChipEEPCmd(iop_base, cmd_reg);
10639 DvcSleepMilliSecond(1);
10640 read_back = AscGetChipEEPCmd(iop_base);
10641 if (read_back == cmd_reg) {
10642 return (1);
10643 }
10644 if (retry++ > ASC_EEP_MAX_RETRY) {
10645 return (0);
10646 }
10647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010648}
10649
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010650static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010651{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010652 ushort read_back;
10653 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010654
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010655 retry = 0;
10656 while (TRUE) {
10657 AscSetChipEEPData(iop_base, data_reg);
10658 DvcSleepMilliSecond(1);
10659 read_back = AscGetChipEEPData(iop_base);
10660 if (read_back == data_reg) {
10661 return (1);
10662 }
10663 if (retry++ > ASC_EEP_MAX_RETRY) {
10664 return (0);
10665 }
10666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010667}
10668
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010669static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010670{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010671 DvcSleepMilliSecond(1);
10672 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010673}
10674
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010675static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010676{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010677 DvcSleepMilliSecond(20);
10678 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010679}
10680
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010681static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010682{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010683 ushort read_wval;
10684 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010685
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010686 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10687 AscWaitEEPRead();
10688 cmd_reg = addr | ASC_EEP_CMD_READ;
10689 AscWriteEEPCmdReg(iop_base, cmd_reg);
10690 AscWaitEEPRead();
10691 read_wval = AscGetChipEEPData(iop_base);
10692 AscWaitEEPRead();
10693 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010694}
10695
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010696static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010697AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010698{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010699 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010700
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010701 read_wval = AscReadEEPWord(iop_base, addr);
10702 if (read_wval != word_val) {
10703 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
10704 AscWaitEEPRead();
10705 AscWriteEEPDataReg(iop_base, word_val);
10706 AscWaitEEPRead();
10707 AscWriteEEPCmdReg(iop_base,
10708 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
10709 AscWaitEEPWrite();
10710 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10711 AscWaitEEPRead();
10712 return (AscReadEEPWord(iop_base, addr));
10713 }
10714 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010715}
10716
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010717static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010718AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010719{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010720 ushort wval;
10721 ushort sum;
10722 ushort *wbuf;
10723 int cfg_beg;
10724 int cfg_end;
10725 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
10726 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010727
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010728 wbuf = (ushort *)cfg_buf;
10729 sum = 0;
10730 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
10731 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10732 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10733 sum += *wbuf;
10734 }
10735 if (bus_type & ASC_IS_VL) {
10736 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10737 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10738 } else {
10739 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10740 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10741 }
10742 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10743 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
10744 if (s_addr <= uchar_end_in_config) {
10745 /*
10746 * Swap all char fields - must unswap bytes already swapped
10747 * by AscReadEEPWord().
10748 */
10749 *wbuf = le16_to_cpu(wval);
10750 } else {
10751 /* Don't swap word field at the end - cntl field. */
10752 *wbuf = wval;
10753 }
10754 sum += wval; /* Checksum treats all EEPROM data as words. */
10755 }
10756 /*
10757 * Read the checksum word which will be compared against 'sum'
10758 * by the caller. Word field already swapped.
10759 */
10760 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10761 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010762}
10763
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010764static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010765AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010766{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010767 int n_error;
10768 ushort *wbuf;
10769 ushort word;
10770 ushort sum;
10771 int s_addr;
10772 int cfg_beg;
10773 int cfg_end;
10774 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010775
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010776 wbuf = (ushort *)cfg_buf;
10777 n_error = 0;
10778 sum = 0;
10779 /* Write two config words; AscWriteEEPWord() will swap bytes. */
10780 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10781 sum += *wbuf;
10782 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10783 n_error++;
10784 }
10785 }
10786 if (bus_type & ASC_IS_VL) {
10787 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10788 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10789 } else {
10790 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10791 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10792 }
10793 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10794 if (s_addr <= uchar_end_in_config) {
10795 /*
10796 * This is a char field. Swap char fields before they are
10797 * swapped again by AscWriteEEPWord().
10798 */
10799 word = cpu_to_le16(*wbuf);
10800 if (word !=
10801 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
10802 n_error++;
10803 }
10804 } else {
10805 /* Don't swap word field at the end - cntl field. */
10806 if (*wbuf !=
10807 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10808 n_error++;
10809 }
10810 }
10811 sum += *wbuf; /* Checksum calculated from word values. */
10812 }
10813 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
10814 *wbuf = sum;
10815 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
10816 n_error++;
10817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010818
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010819 /* Read EEPROM back again. */
10820 wbuf = (ushort *)cfg_buf;
10821 /*
10822 * Read two config words; Byte-swapping done by AscReadEEPWord().
10823 */
10824 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10825 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
10826 n_error++;
10827 }
10828 }
10829 if (bus_type & ASC_IS_VL) {
10830 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10831 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10832 } else {
10833 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10834 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10835 }
10836 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10837 if (s_addr <= uchar_end_in_config) {
10838 /*
10839 * Swap all char fields. Must unswap bytes already swapped
10840 * by AscReadEEPWord().
10841 */
10842 word =
10843 le16_to_cpu(AscReadEEPWord
10844 (iop_base, (uchar)s_addr));
10845 } else {
10846 /* Don't swap word field at the end - cntl field. */
10847 word = AscReadEEPWord(iop_base, (uchar)s_addr);
10848 }
10849 if (*wbuf != word) {
10850 n_error++;
10851 }
10852 }
10853 /* Read checksum; Byte swapping not needed. */
10854 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
10855 n_error++;
10856 }
10857 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010858}
10859
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010860static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010861AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010862{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010863 int retry;
10864 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010865
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010866 retry = 0;
10867 while (TRUE) {
10868 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
10869 bus_type)) == 0) {
10870 break;
10871 }
10872 if (++retry > ASC_EEP_MAX_RETRY) {
10873 break;
10874 }
10875 }
10876 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010877}
10878
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010879static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010880{
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010881 char type = sdev->type;
10882 ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010883
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010884 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
10885 if (!(asc_dvc->init_sdtr & tid_bits)) {
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010886 if ((type == TYPE_ROM) &&
10887 (strncmp(sdev->vendor, "HP ", 3) == 0)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010888 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
10889 }
10890 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010891 if ((type == TYPE_PROCESSOR) ||
10892 (type == TYPE_SCANNER) || (type == TYPE_ROM) ||
10893 (type == TYPE_TAPE)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010894 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
10895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010896
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010897 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
10898 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010899 sdev->id,
10900 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010901 }
10902 }
10903 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010904}
10905
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010906static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010907{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010908 uchar byte_data;
10909 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010910
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010911 if (isodd_word(addr)) {
10912 AscSetChipLramAddr(iop_base, addr - 1);
10913 word_data = AscGetChipLramData(iop_base);
10914 byte_data = (uchar)((word_data >> 8) & 0xFF);
10915 } else {
10916 AscSetChipLramAddr(iop_base, addr);
10917 word_data = AscGetChipLramData(iop_base);
10918 byte_data = (uchar)(word_data & 0xFF);
10919 }
10920 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010921}
Linus Torvalds1da177e2005-04-16 15:20:36 -070010922
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010923static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
10924{
10925 ushort word_data;
10926
10927 AscSetChipLramAddr(iop_base, addr);
10928 word_data = AscGetChipLramData(iop_base);
10929 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010930}
10931
10932#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010933static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010934{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010935 ushort val_low, val_high;
10936 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010937
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010938 AscSetChipLramAddr(iop_base, addr);
10939 val_low = AscGetChipLramData(iop_base);
10940 val_high = AscGetChipLramData(iop_base);
10941 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
10942 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010943}
10944#endif /* CC_VERY_LONG_SG_LIST */
10945
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010946static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010947{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010948 AscSetChipLramAddr(iop_base, addr);
10949 AscSetChipLramData(iop_base, word_val);
10950 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010951}
10952
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010953static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010954{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010955 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010956
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010957 if (isodd_word(addr)) {
10958 addr--;
10959 word_data = AscReadLramWord(iop_base, addr);
10960 word_data &= 0x00FF;
10961 word_data |= (((ushort)byte_val << 8) & 0xFF00);
10962 } else {
10963 word_data = AscReadLramWord(iop_base, addr);
10964 word_data &= 0xFF00;
10965 word_data |= ((ushort)byte_val & 0x00FF);
10966 }
10967 AscWriteLramWord(iop_base, addr, word_data);
10968 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010969}
10970
10971/*
10972 * Copy 2 bytes to LRAM.
10973 *
10974 * The source data is assumed to be in little-endian order in memory
10975 * and is maintained in little-endian order when written to LRAM.
10976 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010977static void
10978AscMemWordCopyPtrToLram(PortAddr iop_base,
10979 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010980{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010981 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010982
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010983 AscSetChipLramAddr(iop_base, s_addr);
10984 for (i = 0; i < 2 * words; i += 2) {
10985 /*
10986 * On a little-endian system the second argument below
10987 * produces a little-endian ushort which is written to
10988 * LRAM in little-endian order. On a big-endian system
10989 * the second argument produces a big-endian ushort which
10990 * is "transparently" byte-swapped by outpw() and written
10991 * in little-endian order to LRAM.
10992 */
10993 outpw(iop_base + IOP_RAM_DATA,
10994 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
10995 }
10996 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010997}
10998
10999/*
11000 * Copy 4 bytes to LRAM.
11001 *
11002 * The source data is assumed to be in little-endian order in memory
11003 * and is maintained in little-endian order when writen to LRAM.
11004 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011005static void
11006AscMemDWordCopyPtrToLram(PortAddr iop_base,
11007 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011008{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011009 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011011 AscSetChipLramAddr(iop_base, s_addr);
11012 for (i = 0; i < 4 * dwords; i += 4) {
11013 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11014 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11015 }
11016 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011017}
11018
11019/*
11020 * Copy 2 bytes from LRAM.
11021 *
11022 * The source data is assumed to be in little-endian order in LRAM
11023 * and is maintained in little-endian order when written to memory.
11024 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011025static void
11026AscMemWordCopyPtrFromLram(PortAddr iop_base,
11027 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011028{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011029 int i;
11030 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011031
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011032 AscSetChipLramAddr(iop_base, s_addr);
11033 for (i = 0; i < 2 * words; i += 2) {
11034 word = inpw(iop_base + IOP_RAM_DATA);
11035 d_buffer[i] = word & 0xff;
11036 d_buffer[i + 1] = (word >> 8) & 0xff;
11037 }
11038 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011039}
11040
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011041static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011042{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011043 ASC_DCNT sum;
11044 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011045
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011046 sum = 0L;
11047 for (i = 0; i < words; i++, s_addr += 2) {
11048 sum += AscReadLramWord(iop_base, s_addr);
11049 }
11050 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011051}
11052
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011053static void
11054AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, 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 < words; i++) {
11060 AscSetChipLramData(iop_base, set_wval);
11061 }
11062 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011063}
11064
Linus Torvalds1da177e2005-04-16 15:20:36 -070011065/*
11066 * --- Adv Library Functions
11067 */
11068
11069/* a_mcode.h */
11070
11071/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011072static unsigned char _adv_asc3550_buf[] = {
11073 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11074 0x01, 0x00, 0x48, 0xe4,
11075 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11076 0x28, 0x0e, 0x9e, 0xe7,
11077 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11078 0x55, 0xf0, 0x01, 0xf6,
11079 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11080 0x00, 0xec, 0x85, 0xf0,
11081 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11082 0x86, 0xf0, 0xb4, 0x00,
11083 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11084 0xaa, 0x18, 0x02, 0x80,
11085 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11086 0x00, 0x57, 0x01, 0xea,
11087 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11088 0x03, 0xe6, 0xb6, 0x00,
11089 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11090 0x02, 0x4a, 0xb9, 0x54,
11091 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11092 0x3e, 0x00, 0x80, 0x00,
11093 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11094 0x74, 0x01, 0x76, 0x01,
11095 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11096 0x4c, 0x1c, 0xbb, 0x55,
11097 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11098 0x03, 0xf7, 0x06, 0xf7,
11099 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11100 0x30, 0x13, 0x64, 0x15,
11101 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11102 0x04, 0xea, 0x5d, 0xf0,
11103 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11104 0xcc, 0x00, 0x20, 0x01,
11105 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11106 0x40, 0x13, 0x30, 0x1c,
11107 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11108 0x59, 0xf0, 0xa7, 0xf0,
11109 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11110 0xa4, 0x00, 0xb5, 0x00,
11111 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11112 0x14, 0x0e, 0x02, 0x10,
11113 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11114 0x10, 0x15, 0x14, 0x15,
11115 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11116 0x91, 0x44, 0x0a, 0x45,
11117 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11118 0x83, 0x59, 0x05, 0xe6,
11119 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11120 0x02, 0xfa, 0x03, 0xfa,
11121 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11122 0x9e, 0x00, 0xa8, 0x00,
11123 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11124 0x7a, 0x01, 0xc0, 0x01,
11125 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11126 0x69, 0x08, 0xba, 0x08,
11127 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11128 0xf1, 0x10, 0x06, 0x12,
11129 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11130 0x8a, 0x15, 0xc6, 0x17,
11131 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11132 0x0e, 0x47, 0x48, 0x47,
11133 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11134 0x14, 0x56, 0x77, 0x57,
11135 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11136 0xf0, 0x29, 0x02, 0xfe,
11137 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11138 0xfe, 0x80, 0x01, 0xff,
11139 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11140 0x00, 0xfe, 0x57, 0x24,
11141 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11142 0x00, 0x00, 0xff, 0x08,
11143 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11144 0xff, 0xff, 0xff, 0x0f,
11145 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11146 0xfe, 0x04, 0xf7, 0xcf,
11147 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11148 0x0b, 0x3c, 0x2a, 0xfe,
11149 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11150 0xfe, 0xf0, 0x01, 0xfe,
11151 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11152 0x02, 0xfe, 0xd4, 0x0c,
11153 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11154 0x1c, 0x05, 0xfe, 0xa6,
11155 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11156 0xf0, 0xfe, 0x86, 0x02,
11157 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11158 0xfe, 0x46, 0xf0, 0xfe,
11159 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11160 0x44, 0x02, 0xfe, 0x44,
11161 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11162 0xa0, 0x17, 0x06, 0x18,
11163 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11164 0x1e, 0x1c, 0xfe, 0xe9,
11165 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11166 0x0a, 0x6b, 0x01, 0x9e,
11167 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11168 0x01, 0x82, 0xfe, 0xbd,
11169 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11170 0x58, 0x1c, 0x17, 0x06,
11171 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11172 0xfe, 0x94, 0x02, 0xfe,
11173 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11174 0x01, 0xfe, 0x54, 0x0f,
11175 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11176 0x69, 0x10, 0x17, 0x06,
11177 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11178 0xf6, 0xc7, 0x01, 0xfe,
11179 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11180 0x02, 0x29, 0x0a, 0x40,
11181 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11182 0x58, 0x0a, 0x99, 0x01,
11183 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11184 0x2a, 0x46, 0xfe, 0x02,
11185 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11186 0x01, 0xfe, 0x07, 0x4b,
11187 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11188 0xfe, 0x56, 0x03, 0xfe,
11189 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11190 0xfe, 0x9f, 0xf0, 0xfe,
11191 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11192 0x1c, 0xeb, 0x09, 0x04,
11193 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11194 0x01, 0x0e, 0xac, 0x75,
11195 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11196 0xfe, 0x82, 0xf0, 0xfe,
11197 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11198 0x32, 0x1f, 0xfe, 0xb4,
11199 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11200 0x0a, 0xf0, 0xfe, 0x7a,
11201 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11202 0x01, 0x33, 0x8f, 0xfe,
11203 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11204 0xf7, 0xfe, 0x48, 0x1c,
11205 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11206 0x0a, 0xca, 0x01, 0x0e,
11207 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11208 0x2c, 0x01, 0x33, 0x8f,
11209 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11210 0xfe, 0x3c, 0x04, 0x1f,
11211 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11212 0x12, 0x2b, 0xff, 0x02,
11213 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11214 0x22, 0x30, 0x2e, 0xd5,
11215 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11216 0xfe, 0x4c, 0x54, 0x64,
11217 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11218 0xfe, 0x2a, 0x13, 0x2f,
11219 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11220 0xd3, 0xfa, 0xef, 0x86,
11221 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11222 0x1d, 0xfe, 0x1c, 0x12,
11223 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11224 0x70, 0x0c, 0x02, 0x22,
11225 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11226 0x01, 0x33, 0x02, 0x29,
11227 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11228 0x80, 0xfe, 0x31, 0xe4,
11229 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11230 0xfe, 0x70, 0x12, 0x49,
11231 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11232 0x80, 0x05, 0xfe, 0x31,
11233 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11234 0x28, 0xfe, 0x42, 0x12,
11235 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11236 0x11, 0xfe, 0xe3, 0x00,
11237 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11238 0x64, 0x05, 0x83, 0x24,
11239 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11240 0x09, 0x48, 0x01, 0x08,
11241 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11242 0x86, 0x24, 0x06, 0x12,
11243 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11244 0x01, 0xa7, 0x14, 0x92,
11245 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11246 0x02, 0x22, 0x05, 0xfe,
11247 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11248 0x47, 0x01, 0xa7, 0x26,
11249 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11250 0x01, 0xfe, 0xaa, 0x14,
11251 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11252 0x05, 0x50, 0xb4, 0x0c,
11253 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11254 0x13, 0x01, 0xfe, 0x14,
11255 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11256 0xff, 0x02, 0x00, 0x57,
11257 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11258 0x72, 0x06, 0x49, 0x04,
11259 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11260 0x06, 0x11, 0x9a, 0x01,
11261 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11262 0x01, 0xa7, 0xec, 0x72,
11263 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11264 0xfe, 0x0a, 0xf0, 0xfe,
11265 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11266 0x8d, 0x81, 0x02, 0x22,
11267 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11268 0x01, 0x08, 0x15, 0x00,
11269 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11270 0x00, 0x02, 0xfe, 0x32,
11271 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11272 0xfe, 0x1b, 0x00, 0x01,
11273 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11274 0x08, 0x15, 0x06, 0x01,
11275 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11276 0x9a, 0x81, 0x4b, 0x1d,
11277 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11278 0x45, 0xfe, 0x32, 0x12,
11279 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11280 0xfe, 0x32, 0x07, 0x8d,
11281 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11282 0x06, 0x15, 0x19, 0x02,
11283 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11284 0x90, 0x77, 0xfe, 0xca,
11285 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11286 0x10, 0xfe, 0x0e, 0x12,
11287 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11288 0x83, 0xe7, 0xc4, 0xa1,
11289 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11290 0x40, 0x12, 0x58, 0x01,
11291 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11292 0x51, 0x83, 0xfb, 0xfe,
11293 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11294 0xfe, 0x40, 0x50, 0xfe,
11295 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11296 0xfe, 0x2a, 0x12, 0xfe,
11297 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11298 0x85, 0x01, 0xa8, 0xfe,
11299 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11300 0x18, 0x57, 0xfb, 0xfe,
11301 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11302 0x0c, 0x39, 0x18, 0x3a,
11303 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11304 0x11, 0x65, 0xfe, 0x48,
11305 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11306 0xdd, 0xb8, 0xfe, 0x80,
11307 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11308 0xfe, 0x7a, 0x08, 0x8d,
11309 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11310 0x10, 0x61, 0x04, 0x06,
11311 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11312 0x12, 0xfe, 0x2e, 0x1c,
11313 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11314 0x52, 0x12, 0xfe, 0x2c,
11315 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11316 0x08, 0xfe, 0x8a, 0x10,
11317 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11318 0x24, 0x0a, 0xab, 0xfe,
11319 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11320 0x1c, 0x12, 0xb5, 0xfe,
11321 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11322 0x1c, 0x06, 0x16, 0x9d,
11323 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11324 0x14, 0x92, 0x01, 0x33,
11325 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11326 0xfe, 0x74, 0x18, 0x1c,
11327 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11328 0x01, 0xe6, 0x1e, 0x27,
11329 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11330 0x09, 0x04, 0x6a, 0xfe,
11331 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11332 0xfe, 0x83, 0x80, 0xfe,
11333 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11334 0x27, 0xfe, 0x40, 0x59,
11335 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11336 0x7c, 0xbe, 0x54, 0xbf,
11337 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11338 0x79, 0x56, 0x68, 0x57,
11339 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11340 0xa2, 0x23, 0x0c, 0x7b,
11341 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11342 0x16, 0xd7, 0x79, 0x39,
11343 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11344 0xfe, 0x10, 0x58, 0xfe,
11345 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
11346 0x19, 0x16, 0xd7, 0x09,
11347 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
11348 0xfe, 0x10, 0x90, 0xfe,
11349 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
11350 0x11, 0x9b, 0x09, 0x04,
11351 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
11352 0xfe, 0x0c, 0x58, 0xfe,
11353 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
11354 0x0b, 0xfe, 0x1a, 0x12,
11355 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
11356 0x14, 0x7a, 0x01, 0x33,
11357 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
11358 0xfe, 0xed, 0x19, 0xbf,
11359 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
11360 0x34, 0xfe, 0x74, 0x10,
11361 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
11362 0x84, 0x05, 0xcb, 0x1c,
11363 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
11364 0xf0, 0xfe, 0xc4, 0x0a,
11365 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
11366 0xce, 0xf0, 0xfe, 0xca,
11367 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
11368 0x22, 0x00, 0x02, 0x5a,
11369 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
11370 0xfe, 0xd0, 0xf0, 0xfe,
11371 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
11372 0x4c, 0xfe, 0x10, 0x10,
11373 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
11374 0x2a, 0x13, 0xfe, 0x4e,
11375 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
11376 0x16, 0x32, 0x2a, 0x73,
11377 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
11378 0x32, 0x8c, 0xfe, 0x48,
11379 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
11380 0xdb, 0x10, 0x11, 0xfe,
11381 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
11382 0x22, 0x30, 0x2e, 0xd8,
11383 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
11384 0x45, 0x0f, 0xfe, 0x42,
11385 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
11386 0x09, 0x04, 0x0b, 0xfe,
11387 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
11388 0x00, 0x21, 0xfe, 0xa6,
11389 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
11390 0xfe, 0xe2, 0x10, 0x01,
11391 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
11392 0x01, 0x6f, 0x02, 0x29,
11393 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
11394 0x01, 0x86, 0x3e, 0x0b,
11395 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
11396 0x3e, 0x0b, 0x0f, 0xfe,
11397 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
11398 0xe8, 0x59, 0x11, 0x2d,
11399 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
11400 0x04, 0x0b, 0x84, 0x3e,
11401 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
11402 0x09, 0x04, 0x1b, 0xfe,
11403 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
11404 0x1c, 0x1c, 0xfe, 0x9d,
11405 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
11406 0xfe, 0x15, 0x00, 0xfe,
11407 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
11408 0x0f, 0xfe, 0x47, 0x00,
11409 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
11410 0xab, 0x70, 0x05, 0x6b,
11411 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
11412 0x1c, 0x42, 0x59, 0x01,
11413 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
11414 0x00, 0x37, 0x97, 0x01,
11415 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
11416 0x1d, 0xfe, 0xce, 0x45,
11417 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
11418 0x57, 0x05, 0x51, 0xfe,
11419 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
11420 0x46, 0x09, 0x04, 0x1d,
11421 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
11422 0x99, 0x01, 0x0e, 0xfe,
11423 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
11424 0xfe, 0xee, 0x14, 0xee,
11425 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
11426 0x13, 0x02, 0x29, 0x1e,
11427 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
11428 0xce, 0x1e, 0x2d, 0x47,
11429 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
11430 0x12, 0x4d, 0x01, 0xfe,
11431 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
11432 0xf0, 0x0d, 0xfe, 0x02,
11433 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
11434 0xf6, 0xfe, 0x34, 0x01,
11435 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
11436 0xaf, 0xfe, 0x02, 0xea,
11437 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
11438 0x05, 0xfe, 0x38, 0x01,
11439 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
11440 0x0c, 0xfe, 0x62, 0x01,
11441 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
11442 0x03, 0x23, 0x03, 0x1e,
11443 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
11444 0x71, 0x13, 0xfe, 0x24,
11445 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
11446 0xdc, 0xfe, 0x73, 0x57,
11447 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
11448 0x80, 0x5d, 0x03, 0xfe,
11449 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
11450 0x75, 0x03, 0x09, 0x04,
11451 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
11452 0xfe, 0x1e, 0x80, 0xe1,
11453 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
11454 0x90, 0xa3, 0xfe, 0x3c,
11455 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
11456 0x16, 0x2f, 0x07, 0x2d,
11457 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
11458 0xe8, 0x11, 0xfe, 0xe9,
11459 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
11460 0x1e, 0x1c, 0xfe, 0x14,
11461 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
11462 0x09, 0x04, 0x4f, 0xfe,
11463 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
11464 0x40, 0x12, 0x20, 0x63,
11465 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
11466 0x1c, 0x05, 0xfe, 0xac,
11467 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
11468 0xfe, 0xb0, 0x00, 0xfe,
11469 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
11470 0x24, 0x69, 0x12, 0xc9,
11471 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
11472 0x90, 0x4d, 0xfe, 0x91,
11473 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
11474 0xfe, 0x90, 0x4d, 0xfe,
11475 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
11476 0x46, 0x1e, 0x20, 0xed,
11477 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
11478 0x70, 0xfe, 0x14, 0x1c,
11479 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
11480 0xfe, 0x07, 0xe6, 0x1d,
11481 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
11482 0xfa, 0xef, 0xfe, 0x42,
11483 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
11484 0xfe, 0x36, 0x12, 0xf0,
11485 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
11486 0x3d, 0x75, 0x07, 0x10,
11487 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
11488 0x10, 0x07, 0x7e, 0x45,
11489 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
11490 0xfe, 0x01, 0xec, 0x97,
11491 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
11492 0x27, 0x01, 0xda, 0xfe,
11493 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
11494 0xfe, 0x48, 0x12, 0x07,
11495 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
11496 0xfe, 0x3e, 0x11, 0x07,
11497 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
11498 0x11, 0x07, 0x19, 0xfe,
11499 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
11500 0x01, 0x08, 0x8c, 0x43,
11501 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
11502 0x7e, 0x02, 0x29, 0x2b,
11503 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
11504 0xfc, 0x10, 0x09, 0x04,
11505 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
11506 0xc6, 0x10, 0x1e, 0x58,
11507 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
11508 0x54, 0x18, 0x55, 0x23,
11509 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
11510 0xa5, 0xc0, 0x38, 0xc1,
11511 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
11512 0x05, 0xfa, 0x4e, 0xfe,
11513 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
11514 0x0c, 0x56, 0x18, 0x57,
11515 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
11516 0x00, 0x56, 0xfe, 0xa1,
11517 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
11518 0x58, 0xfe, 0x1f, 0x40,
11519 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
11520 0x31, 0x57, 0xfe, 0x44,
11521 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
11522 0x8a, 0x50, 0x05, 0x39,
11523 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
11524 0x12, 0xcd, 0x02, 0x5b,
11525 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
11526 0x2f, 0x07, 0x9b, 0x21,
11527 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
11528 0x39, 0x68, 0x3a, 0xfe,
11529 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
11530 0x51, 0xfe, 0x8e, 0x51,
11531 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
11532 0x01, 0x08, 0x25, 0x32,
11533 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
11534 0x3b, 0x02, 0x44, 0x01,
11535 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
11536 0x01, 0x08, 0x1f, 0xa2,
11537 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
11538 0x00, 0x28, 0x84, 0x49,
11539 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
11540 0x78, 0x3d, 0xfe, 0xda,
11541 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
11542 0x05, 0xc6, 0x28, 0x84,
11543 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
11544 0x14, 0xfe, 0x03, 0x17,
11545 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
11546 0xfe, 0xaa, 0x14, 0x02,
11547 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
11548 0x21, 0x44, 0x01, 0xfe,
11549 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
11550 0xfe, 0x4a, 0xf4, 0x0b,
11551 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
11552 0x85, 0x02, 0x5b, 0x05,
11553 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
11554 0xd8, 0x14, 0x02, 0x5c,
11555 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
11556 0x01, 0x08, 0x23, 0x72,
11557 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
11558 0x12, 0x5e, 0x2b, 0x01,
11559 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
11560 0x1c, 0xfe, 0xff, 0x7f,
11561 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
11562 0x57, 0x48, 0x8b, 0x1c,
11563 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
11564 0x00, 0x57, 0x48, 0x8b,
11565 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
11566 0x03, 0x0a, 0x50, 0x01,
11567 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
11568 0x54, 0xfe, 0x00, 0xf4,
11569 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
11570 0x03, 0x7c, 0x63, 0x27,
11571 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
11572 0xfe, 0x82, 0x4a, 0xfe,
11573 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
11574 0x42, 0x48, 0x5f, 0x60,
11575 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
11576 0x1f, 0xfe, 0xa2, 0x14,
11577 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
11578 0xcc, 0x12, 0x49, 0x04,
11579 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
11580 0xe8, 0x13, 0x3b, 0x13,
11581 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
11582 0xa1, 0xff, 0x02, 0x83,
11583 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
11584 0x13, 0x06, 0xfe, 0x56,
11585 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
11586 0x64, 0x00, 0x17, 0x93,
11587 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
11588 0xc8, 0x00, 0x8e, 0xe4,
11589 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
11590 0x01, 0xba, 0xfe, 0x4e,
11591 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
11592 0xfe, 0x60, 0x14, 0xfe,
11593 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
11594 0xfe, 0x22, 0x13, 0x1c,
11595 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
11596 0xfe, 0x9c, 0x14, 0xb7,
11597 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
11598 0xfe, 0x9c, 0x14, 0xb7,
11599 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
11600 0xfe, 0xb4, 0x56, 0xfe,
11601 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
11602 0xe5, 0x15, 0x0b, 0x01,
11603 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
11604 0x49, 0x01, 0x08, 0x03,
11605 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
11606 0x15, 0x06, 0x01, 0x08,
11607 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
11608 0x4a, 0x01, 0x08, 0x03,
11609 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
11610 0xfe, 0x49, 0xf4, 0x00,
11611 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
11612 0x08, 0x2f, 0x07, 0xfe,
11613 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
11614 0x01, 0x43, 0x1e, 0xcd,
11615 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11616 0xed, 0x88, 0x07, 0x10,
11617 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
11618 0x80, 0x01, 0x0e, 0x88,
11619 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
11620 0x88, 0x03, 0x0a, 0x42,
11621 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11622 0xfe, 0x80, 0x80, 0xf2,
11623 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
11624 0x01, 0x82, 0x03, 0x17,
11625 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
11626 0xfe, 0x24, 0x1c, 0xfe,
11627 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
11628 0x91, 0x1d, 0x66, 0xfe,
11629 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
11630 0xda, 0x10, 0x17, 0x10,
11631 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
11632 0x05, 0xfe, 0x66, 0x01,
11633 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
11634 0xfe, 0x3c, 0x50, 0x66,
11635 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
11636 0x40, 0x16, 0xfe, 0xb6,
11637 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
11638 0x10, 0x71, 0xfe, 0x83,
11639 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
11640 0xfe, 0x62, 0x16, 0xfe,
11641 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
11642 0xfe, 0x98, 0xe7, 0x00,
11643 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
11644 0xfe, 0x30, 0xbc, 0xfe,
11645 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
11646 0xc5, 0x90, 0xfe, 0x9a,
11647 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
11648 0x42, 0x10, 0xfe, 0x02,
11649 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
11650 0xfe, 0x1d, 0xf7, 0x4f,
11651 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
11652 0x47, 0xfe, 0x83, 0x58,
11653 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
11654 0xfe, 0xdd, 0x00, 0x63,
11655 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
11656 0x06, 0x37, 0x95, 0xa9,
11657 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
11658 0x18, 0x1c, 0x1a, 0x5d,
11659 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
11660 0xe1, 0x10, 0x78, 0x2c,
11661 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
11662 0x13, 0x3c, 0x8a, 0x0a,
11663 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
11664 0xe3, 0xfe, 0x00, 0xcc,
11665 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
11666 0x0e, 0xf2, 0x01, 0x6f,
11667 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
11668 0xf6, 0xfe, 0xd6, 0xf0,
11669 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
11670 0x15, 0x00, 0x59, 0x76,
11671 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
11672 0x11, 0x2d, 0x01, 0x6f,
11673 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
11674 0xc8, 0xfe, 0x48, 0x55,
11675 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
11676 0x99, 0x01, 0x0e, 0xf0,
11677 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
11678 0x75, 0x03, 0x0a, 0x42,
11679 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
11680 0x0e, 0x73, 0x75, 0x03,
11681 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
11682 0xfe, 0x3a, 0x45, 0x5b,
11683 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
11684 0xfe, 0x02, 0xe6, 0x1b,
11685 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
11686 0xfe, 0x94, 0x00, 0xfe,
11687 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
11688 0xe6, 0x2c, 0xfe, 0x4e,
11689 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
11690 0x03, 0x07, 0x7a, 0xfe,
11691 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
11692 0x07, 0x1b, 0xfe, 0x5a,
11693 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
11694 0x24, 0x2c, 0xdc, 0x07,
11695 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
11696 0x9f, 0xad, 0x03, 0x14,
11697 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
11698 0x03, 0x25, 0xfe, 0xca,
11699 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
11700 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011701};
11702
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011703static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
11704static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011705
11706/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011707static unsigned char _adv_asc38C0800_buf[] = {
11708 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
11709 0x01, 0x00, 0x48, 0xe4,
11710 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
11711 0x1c, 0x0f, 0x00, 0xf6,
11712 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
11713 0x09, 0xe7, 0x55, 0xf0,
11714 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
11715 0x18, 0xf4, 0x08, 0x00,
11716 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
11717 0x86, 0xf0, 0xb1, 0xf0,
11718 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
11719 0x3c, 0x00, 0xbb, 0x00,
11720 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
11721 0xba, 0x13, 0x18, 0x40,
11722 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
11723 0x6e, 0x01, 0x74, 0x01,
11724 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
11725 0xc0, 0x00, 0x01, 0x01,
11726 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
11727 0x08, 0x12, 0x02, 0x4a,
11728 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
11729 0x5d, 0xf0, 0x02, 0xfa,
11730 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
11731 0x68, 0x01, 0x6a, 0x01,
11732 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
11733 0x06, 0x13, 0x4c, 0x1c,
11734 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
11735 0x0f, 0x00, 0x47, 0x00,
11736 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
11737 0x4e, 0x1c, 0x10, 0x44,
11738 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
11739 0x05, 0x00, 0x34, 0x00,
11740 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
11741 0x42, 0x0c, 0x12, 0x0f,
11742 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
11743 0x00, 0x4e, 0x42, 0x54,
11744 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11745 0x59, 0xf0, 0xb8, 0xf0,
11746 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
11747 0x19, 0x00, 0x33, 0x00,
11748 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
11749 0xe7, 0x00, 0xe2, 0x03,
11750 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
11751 0x12, 0x13, 0x24, 0x14,
11752 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
11753 0x36, 0x1c, 0x08, 0x44,
11754 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
11755 0x3a, 0x55, 0x83, 0x55,
11756 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
11757 0x0c, 0xf0, 0x04, 0xf8,
11758 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
11759 0xa8, 0x00, 0xaa, 0x00,
11760 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
11761 0xc4, 0x01, 0xc6, 0x01,
11762 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
11763 0x68, 0x08, 0x69, 0x08,
11764 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
11765 0xed, 0x10, 0xf1, 0x10,
11766 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
11767 0x1e, 0x13, 0x46, 0x14,
11768 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
11769 0xca, 0x18, 0xe6, 0x19,
11770 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
11771 0xf0, 0x2b, 0x02, 0xfe,
11772 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
11773 0xfe, 0x84, 0x01, 0xff,
11774 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11775 0x00, 0xfe, 0x57, 0x24,
11776 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
11777 0x00, 0x00, 0xff, 0x08,
11778 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11779 0xff, 0xff, 0xff, 0x11,
11780 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11781 0xfe, 0x04, 0xf7, 0xd6,
11782 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
11783 0x0a, 0x42, 0x2c, 0xfe,
11784 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
11785 0xfe, 0xf4, 0x01, 0xfe,
11786 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
11787 0x02, 0xfe, 0xc8, 0x0d,
11788 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11789 0x1c, 0x03, 0xfe, 0xa6,
11790 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
11791 0xf0, 0xfe, 0x8a, 0x02,
11792 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
11793 0xfe, 0x46, 0xf0, 0xfe,
11794 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11795 0x48, 0x02, 0xfe, 0x44,
11796 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
11797 0xaa, 0x18, 0x06, 0x14,
11798 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
11799 0x1e, 0x1c, 0xfe, 0xe9,
11800 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
11801 0x09, 0x70, 0x01, 0xa8,
11802 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
11803 0x01, 0x87, 0xfe, 0xbd,
11804 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11805 0x58, 0x1c, 0x18, 0x06,
11806 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
11807 0xfe, 0x98, 0x02, 0xfe,
11808 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
11809 0x01, 0xfe, 0x48, 0x10,
11810 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
11811 0x69, 0x10, 0x18, 0x06,
11812 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
11813 0xf6, 0xce, 0x01, 0xfe,
11814 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
11815 0x82, 0x16, 0x02, 0x2b,
11816 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
11817 0xfe, 0x41, 0x58, 0x09,
11818 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
11819 0x82, 0x16, 0x02, 0x2b,
11820 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
11821 0xfe, 0x77, 0x57, 0xfe,
11822 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
11823 0xfe, 0x40, 0x1c, 0x1c,
11824 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
11825 0x03, 0xfe, 0x11, 0xf0,
11826 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
11827 0xfe, 0x11, 0x00, 0x02,
11828 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
11829 0x21, 0x22, 0xa3, 0xb7,
11830 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
11831 0x12, 0xd1, 0x1c, 0xd9,
11832 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
11833 0xfe, 0xe4, 0x00, 0x27,
11834 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
11835 0x06, 0xf0, 0xfe, 0xc8,
11836 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
11837 0x70, 0x28, 0x17, 0xfe,
11838 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
11839 0xf9, 0x2c, 0x99, 0x19,
11840 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
11841 0x74, 0x01, 0xaf, 0x8c,
11842 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
11843 0x8d, 0x51, 0x64, 0x79,
11844 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
11845 0xfe, 0x6a, 0x02, 0x02,
11846 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
11847 0xfe, 0x3c, 0x04, 0x3b,
11848 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
11849 0x00, 0x10, 0x01, 0x0b,
11850 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
11851 0xfe, 0x4c, 0x44, 0xfe,
11852 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
11853 0xda, 0x4f, 0x79, 0x2a,
11854 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
11855 0xfe, 0x2a, 0x13, 0x32,
11856 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
11857 0x54, 0x6b, 0xda, 0xfe,
11858 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
11859 0x08, 0x13, 0x32, 0x07,
11860 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
11861 0x08, 0x05, 0x06, 0x4d,
11862 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
11863 0x2d, 0x12, 0xfe, 0xe6,
11864 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
11865 0x02, 0x2b, 0xfe, 0x42,
11866 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
11867 0xfe, 0x87, 0x80, 0xfe,
11868 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
11869 0x07, 0x19, 0xfe, 0x7c,
11870 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
11871 0x17, 0xfe, 0x90, 0x05,
11872 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
11873 0xa0, 0x00, 0x28, 0xfe,
11874 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
11875 0x34, 0xfe, 0x89, 0x48,
11876 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
11877 0x12, 0xfe, 0xe3, 0x00,
11878 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11879 0x70, 0x05, 0x88, 0x25,
11880 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
11881 0x09, 0x48, 0xff, 0x02,
11882 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
11883 0x08, 0x53, 0x05, 0xcb,
11884 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
11885 0x05, 0x1b, 0xfe, 0x22,
11886 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
11887 0x0d, 0x00, 0x01, 0x36,
11888 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
11889 0x03, 0x5c, 0x28, 0xfe,
11890 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
11891 0x05, 0x1f, 0xfe, 0x02,
11892 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
11893 0x01, 0x4b, 0x12, 0xfe,
11894 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
11895 0x12, 0x03, 0x45, 0x28,
11896 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
11897 0x43, 0x48, 0xc4, 0xcc,
11898 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
11899 0x6e, 0x41, 0x01, 0xb2,
11900 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
11901 0xfe, 0xcc, 0x15, 0x1d,
11902 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
11903 0x45, 0xc1, 0x0c, 0x45,
11904 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
11905 0xe2, 0x00, 0x27, 0xdb,
11906 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
11907 0xfe, 0x06, 0xf0, 0xfe,
11908 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
11909 0x16, 0x19, 0x01, 0x0b,
11910 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
11911 0xfe, 0x99, 0xa4, 0x01,
11912 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
11913 0x12, 0x08, 0x05, 0x1a,
11914 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
11915 0x0b, 0x16, 0x00, 0x01,
11916 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
11917 0xe2, 0x6c, 0x58, 0xbe,
11918 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
11919 0xfe, 0x09, 0x6f, 0xba,
11920 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
11921 0xfe, 0x54, 0x07, 0x1c,
11922 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
11923 0x07, 0x02, 0x24, 0x01,
11924 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
11925 0x2c, 0x90, 0xfe, 0xae,
11926 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
11927 0x37, 0x22, 0x20, 0x07,
11928 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
11929 0xfe, 0x06, 0x10, 0xfe,
11930 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
11931 0x37, 0x01, 0xb3, 0xb8,
11932 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
11933 0x50, 0xfe, 0x44, 0x51,
11934 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
11935 0x14, 0x5f, 0xfe, 0x0c,
11936 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
11937 0x14, 0x3e, 0xfe, 0x4a,
11938 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11939 0x90, 0x0c, 0x60, 0x14,
11940 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
11941 0xfe, 0x44, 0x90, 0xfe,
11942 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
11943 0x0c, 0x5e, 0x14, 0x5f,
11944 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
11945 0x14, 0x3c, 0x21, 0x0c,
11946 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
11947 0x27, 0xdd, 0xfe, 0x9e,
11948 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
11949 0x9a, 0x08, 0xc6, 0xfe,
11950 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
11951 0x95, 0x86, 0x02, 0x24,
11952 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
11953 0x06, 0xfe, 0x10, 0x12,
11954 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
11955 0x1c, 0x02, 0xfe, 0x18,
11956 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
11957 0x2c, 0x1c, 0xfe, 0xaa,
11958 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
11959 0xde, 0x09, 0xfe, 0xb7,
11960 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
11961 0xfe, 0xf1, 0x18, 0xfe,
11962 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
11963 0x14, 0x59, 0xfe, 0x95,
11964 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
11965 0xfe, 0xf0, 0x08, 0xb5,
11966 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
11967 0x0b, 0xb6, 0xfe, 0xbf,
11968 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
11969 0x12, 0xc2, 0xfe, 0xd2,
11970 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
11971 0x06, 0x17, 0x85, 0xc5,
11972 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
11973 0x9d, 0x01, 0x36, 0x10,
11974 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
11975 0x98, 0x80, 0xfe, 0x19,
11976 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
11977 0xfe, 0x44, 0x54, 0xbe,
11978 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
11979 0x02, 0x4a, 0x08, 0x05,
11980 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
11981 0x9c, 0x3c, 0xfe, 0x6c,
11982 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
11983 0x3b, 0x40, 0x03, 0x49,
11984 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
11985 0x8f, 0xfe, 0xe3, 0x54,
11986 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
11987 0xda, 0x09, 0xfe, 0x8b,
11988 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
11989 0x0a, 0x3a, 0x49, 0x3b,
11990 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
11991 0xad, 0xfe, 0x01, 0x59,
11992 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
11993 0x49, 0x8f, 0xfe, 0xe3,
11994 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
11995 0x4a, 0x3a, 0x49, 0x3b,
11996 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
11997 0x02, 0x4a, 0x08, 0x05,
11998 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
11999 0xb7, 0xfe, 0x03, 0xa1,
12000 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12001 0xfe, 0x86, 0x91, 0x6a,
12002 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12003 0x61, 0x0c, 0x7f, 0x14,
12004 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12005 0x9b, 0x2e, 0x9c, 0x3c,
12006 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12007 0xfa, 0x3c, 0x01, 0xef,
12008 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12009 0xe4, 0x08, 0x05, 0x1f,
12010 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12011 0x03, 0x5e, 0x29, 0x5f,
12012 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12013 0xf4, 0x09, 0x08, 0x05,
12014 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12015 0x81, 0x50, 0xfe, 0x10,
12016 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12017 0x08, 0x09, 0x12, 0xa6,
12018 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12019 0x08, 0x09, 0xfe, 0x0c,
12020 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12021 0x08, 0x05, 0x0a, 0xfe,
12022 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12023 0xf0, 0xe2, 0x15, 0x7e,
12024 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12025 0x57, 0x3d, 0xfe, 0xed,
12026 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12027 0x00, 0xff, 0x35, 0xfe,
12028 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12029 0x1e, 0x19, 0x8a, 0x03,
12030 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12031 0xfe, 0xd1, 0xf0, 0xfe,
12032 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12033 0x10, 0xfe, 0xce, 0xf0,
12034 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12035 0x10, 0xfe, 0x22, 0x00,
12036 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12037 0x02, 0x65, 0xfe, 0xd0,
12038 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12039 0x0b, 0x10, 0x58, 0xfe,
12040 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12041 0x12, 0x00, 0x2c, 0x0f,
12042 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12043 0x0c, 0xbc, 0x17, 0x34,
12044 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12045 0x0c, 0x1c, 0x34, 0x94,
12046 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12047 0x4b, 0xfe, 0xdb, 0x10,
12048 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12049 0x89, 0xf0, 0x24, 0x33,
12050 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12051 0x33, 0x31, 0xdf, 0xbc,
12052 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12053 0x17, 0xfe, 0x2c, 0x0d,
12054 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12055 0x12, 0x55, 0xfe, 0x28,
12056 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12057 0x44, 0xfe, 0x28, 0x00,
12058 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12059 0x0f, 0x64, 0x12, 0x2f,
12060 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12061 0x0a, 0xfe, 0xb4, 0x10,
12062 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12063 0xfe, 0x34, 0x46, 0xac,
12064 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12065 0x37, 0x01, 0xf5, 0x01,
12066 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12067 0xfe, 0x2e, 0x03, 0x08,
12068 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12069 0x1a, 0xfe, 0x58, 0x12,
12070 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12071 0xfe, 0x50, 0x0d, 0xfe,
12072 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12073 0xfe, 0xa9, 0x10, 0x10,
12074 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12075 0xfe, 0x13, 0x00, 0xfe,
12076 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12077 0x24, 0x00, 0x8c, 0xb5,
12078 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12079 0xfe, 0x9d, 0x41, 0xfe,
12080 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12081 0xb4, 0x15, 0xfe, 0x31,
12082 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12083 0xec, 0xd0, 0xfc, 0x44,
12084 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12085 0x4b, 0x91, 0xfe, 0x75,
12086 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12087 0x0e, 0xfe, 0x44, 0x48,
12088 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12089 0xfe, 0x41, 0x58, 0x09,
12090 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12091 0x2e, 0x03, 0x09, 0x5d,
12092 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12093 0xce, 0x47, 0xfe, 0xad,
12094 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12095 0x59, 0x13, 0x9f, 0x13,
12096 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12097 0xe0, 0x0e, 0x0f, 0x06,
12098 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12099 0x3a, 0x01, 0x56, 0xfe,
12100 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12101 0x20, 0x4f, 0xfe, 0x05,
12102 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12103 0x48, 0xf4, 0x0d, 0xfe,
12104 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12105 0x15, 0x1a, 0x39, 0xa0,
12106 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12107 0x0c, 0xfe, 0x60, 0x01,
12108 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12109 0x06, 0x13, 0x2f, 0x12,
12110 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12111 0x22, 0x9f, 0xb7, 0x13,
12112 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12113 0xa0, 0xb4, 0xfe, 0xd9,
12114 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12115 0xc3, 0xfe, 0x03, 0xdc,
12116 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12117 0xfe, 0x00, 0xcc, 0x04,
12118 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12119 0xfe, 0x1c, 0x80, 0x07,
12120 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12121 0xfe, 0x0c, 0x90, 0xfe,
12122 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12123 0x0a, 0xfe, 0x3c, 0x50,
12124 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12125 0x16, 0x08, 0x05, 0x1b,
12126 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12127 0xfe, 0x2c, 0x13, 0x01,
12128 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12129 0x0c, 0xfe, 0x64, 0x01,
12130 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12131 0x80, 0x8d, 0xfe, 0x01,
12132 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12133 0x22, 0x20, 0xfb, 0x79,
12134 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12135 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012136
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012137 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12138 0xb2, 0x00, 0xfe, 0x09,
12139 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12140 0x45, 0x0f, 0x46, 0x52,
12141 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12142 0x0f, 0x44, 0x11, 0x0f,
12143 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12144 0x25, 0x11, 0x13, 0x20,
12145 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12146 0x56, 0xfe, 0xd6, 0xf0,
12147 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12148 0x18, 0x1c, 0x04, 0x42,
12149 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12150 0xf5, 0x13, 0x04, 0x01,
12151 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12152 0x13, 0x32, 0x07, 0x2f,
12153 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12154 0x41, 0x48, 0xfe, 0x45,
12155 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12156 0x07, 0x11, 0xac, 0x09,
12157 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12158 0x82, 0x4e, 0xfe, 0x14,
12159 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12160 0xfe, 0x01, 0xec, 0xa2,
12161 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12162 0x2a, 0x01, 0xe3, 0xfe,
12163 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12164 0xfe, 0x48, 0x12, 0x07,
12165 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12166 0xfe, 0x32, 0x12, 0x07,
12167 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12168 0x1f, 0xfe, 0x12, 0x12,
12169 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12170 0x94, 0x4b, 0x04, 0x2d,
12171 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12172 0x32, 0x07, 0xa6, 0xfe,
12173 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12174 0x5a, 0xfe, 0x72, 0x12,
12175 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12176 0xfe, 0x26, 0x13, 0x03,
12177 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12178 0x0c, 0x7f, 0x0c, 0x80,
12179 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12180 0x3c, 0xfe, 0x04, 0x55,
12181 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12182 0x91, 0x10, 0x03, 0x3f,
12183 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12184 0x88, 0x9b, 0x2e, 0x9c,
12185 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12186 0x56, 0x0c, 0x5e, 0x14,
12187 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12188 0x03, 0x60, 0x29, 0x61,
12189 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12190 0x50, 0xfe, 0xc6, 0x50,
12191 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12192 0x29, 0x3e, 0xfe, 0x40,
12193 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12194 0x2d, 0x01, 0x0b, 0x1d,
12195 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12196 0x72, 0x01, 0xaf, 0x1e,
12197 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12198 0x0a, 0x55, 0x35, 0xfe,
12199 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12200 0x02, 0x72, 0xfe, 0x19,
12201 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12202 0x1d, 0xe8, 0x33, 0x31,
12203 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12204 0x0b, 0x1c, 0x34, 0x1d,
12205 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12206 0x33, 0x31, 0xfe, 0xe8,
12207 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12208 0x05, 0x1f, 0x35, 0xa9,
12209 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12210 0x14, 0x01, 0xaf, 0x8c,
12211 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12212 0x03, 0x45, 0x28, 0x35,
12213 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12214 0x03, 0x5c, 0xc1, 0x0c,
12215 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12216 0x89, 0x01, 0x0b, 0x1c,
12217 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12218 0xfe, 0x42, 0x58, 0xf1,
12219 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12220 0xf4, 0x06, 0xea, 0x32,
12221 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12222 0x01, 0x0b, 0x26, 0x89,
12223 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12224 0x26, 0xfe, 0xd4, 0x13,
12225 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12226 0x13, 0x1c, 0xfe, 0xd0,
12227 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12228 0x0f, 0x71, 0xff, 0x02,
12229 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12230 0x00, 0x5c, 0x04, 0x0f,
12231 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12232 0xfe, 0x00, 0x5c, 0x04,
12233 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12234 0x02, 0x00, 0x57, 0x52,
12235 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12236 0x87, 0x04, 0xfe, 0x03,
12237 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12238 0xfe, 0x00, 0x7d, 0xfe,
12239 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12240 0x14, 0x5f, 0x57, 0x3f,
12241 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12242 0x5a, 0x8d, 0x04, 0x01,
12243 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12244 0xfe, 0x96, 0x15, 0x33,
12245 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12246 0x0a, 0xfe, 0xc1, 0x59,
12247 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12248 0x21, 0x69, 0x1a, 0xee,
12249 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12250 0x30, 0xfe, 0x78, 0x10,
12251 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12252 0x98, 0xfe, 0x30, 0x00,
12253 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12254 0x98, 0xfe, 0x64, 0x00,
12255 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12256 0x10, 0x69, 0x06, 0xfe,
12257 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12258 0x18, 0x59, 0x0f, 0x06,
12259 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12260 0x43, 0xf4, 0x9f, 0xfe,
12261 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12262 0x9e, 0xfe, 0xf3, 0x10,
12263 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12264 0x17, 0xfe, 0x4d, 0xe4,
12265 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12266 0x17, 0xfe, 0x4d, 0xe4,
12267 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12268 0xf4, 0x00, 0xe9, 0x91,
12269 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12270 0x04, 0x16, 0x06, 0x01,
12271 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12272 0x0b, 0x26, 0xf3, 0x76,
12273 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12274 0x16, 0x19, 0x01, 0x0b,
12275 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12276 0x0b, 0x26, 0xb1, 0x76,
12277 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12278 0xfe, 0x48, 0x13, 0xb8,
12279 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12280 0xec, 0xfe, 0x27, 0x01,
12281 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12282 0x07, 0xfe, 0xe3, 0x00,
12283 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12284 0x22, 0xd4, 0x07, 0x06,
12285 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12286 0x07, 0x11, 0xae, 0x09,
12287 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12288 0x0e, 0x8e, 0xfe, 0x80,
12289 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12290 0x09, 0x48, 0x01, 0x0e,
12291 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12292 0x80, 0xfe, 0x80, 0x4c,
12293 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12294 0x09, 0x5d, 0x01, 0x87,
12295 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12296 0x19, 0xde, 0xfe, 0x24,
12297 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12298 0x17, 0xad, 0x9a, 0x1b,
12299 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12300 0x16, 0xfe, 0xda, 0x10,
12301 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12302 0x18, 0x58, 0x03, 0xfe,
12303 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12304 0xf4, 0x06, 0xfe, 0x3c,
12305 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12306 0x97, 0xfe, 0x38, 0x17,
12307 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12308 0x10, 0x18, 0x11, 0x75,
12309 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12310 0x2e, 0x97, 0xfe, 0x5a,
12311 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12312 0xfe, 0x98, 0xe7, 0x00,
12313 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12314 0xfe, 0x30, 0xbc, 0xfe,
12315 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12316 0xcb, 0x97, 0xfe, 0x92,
12317 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12318 0x42, 0x10, 0xfe, 0x02,
12319 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12320 0x03, 0xa1, 0xfe, 0x1d,
12321 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12322 0x9a, 0x5b, 0x41, 0xfe,
12323 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12324 0x11, 0x12, 0xfe, 0xdd,
12325 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12326 0x17, 0x15, 0x06, 0x39,
12327 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12328 0xfe, 0x7e, 0x18, 0x1e,
12329 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12330 0x12, 0xfe, 0xe1, 0x10,
12331 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12332 0x13, 0x42, 0x92, 0x09,
12333 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12334 0xf0, 0xfe, 0x00, 0xcc,
12335 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12336 0x0e, 0xfe, 0x80, 0x4c,
12337 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12338 0x24, 0x12, 0xfe, 0x14,
12339 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12340 0xe7, 0x0a, 0x10, 0xfe,
12341 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12342 0x08, 0x54, 0x1b, 0x37,
12343 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12344 0x90, 0x3a, 0xce, 0x3b,
12345 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
12346 0x13, 0xa3, 0x04, 0x09,
12347 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
12348 0x44, 0x17, 0xfe, 0xe8,
12349 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
12350 0x5d, 0x01, 0xa8, 0x09,
12351 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
12352 0x1c, 0x19, 0x03, 0xfe,
12353 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
12354 0x6b, 0xfe, 0x2e, 0x19,
12355 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
12356 0xfe, 0x0b, 0x00, 0x6b,
12357 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
12358 0x08, 0x10, 0x03, 0xfe,
12359 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
12360 0x04, 0x68, 0x54, 0xe7,
12361 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
12362 0x1a, 0xf4, 0xfe, 0x00,
12363 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
12364 0x04, 0x07, 0x7e, 0xfe,
12365 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12366 0x07, 0x1a, 0xfe, 0x5a,
12367 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
12368 0x25, 0x6d, 0xe5, 0x07,
12369 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
12370 0xa9, 0xb8, 0x04, 0x15,
12371 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
12372 0x40, 0x5c, 0x04, 0x1c,
12373 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
12374 0xf7, 0xfe, 0x82, 0xf0,
12375 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012376};
12377
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012378static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
12379static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012380
12381/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012382static unsigned char _adv_asc38C1600_buf[] = {
12383 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
12384 0x18, 0xe4, 0x01, 0x00,
12385 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
12386 0x07, 0x17, 0xc0, 0x5f,
12387 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
12388 0x85, 0xf0, 0x86, 0xf0,
12389 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
12390 0x98, 0x57, 0x01, 0xe6,
12391 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
12392 0x38, 0x54, 0x32, 0xf0,
12393 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
12394 0x00, 0xe6, 0xb1, 0xf0,
12395 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
12396 0x06, 0x13, 0x0c, 0x1c,
12397 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
12398 0xb9, 0x54, 0x00, 0x80,
12399 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
12400 0x03, 0xe6, 0x01, 0xea,
12401 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
12402 0x04, 0x13, 0xbb, 0x55,
12403 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
12404 0xbb, 0x00, 0xc0, 0x00,
12405 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
12406 0x4c, 0x1c, 0x4e, 0x1c,
12407 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
12408 0x24, 0x01, 0x3c, 0x01,
12409 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
12410 0x78, 0x01, 0x7c, 0x01,
12411 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
12412 0x6e, 0x1e, 0x02, 0x48,
12413 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
12414 0x03, 0xfc, 0x06, 0x00,
12415 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
12416 0x30, 0x1c, 0x38, 0x1c,
12417 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
12418 0x5d, 0xf0, 0xa7, 0xf0,
12419 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
12420 0x33, 0x00, 0x34, 0x00,
12421 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
12422 0x79, 0x01, 0x3c, 0x09,
12423 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
12424 0x40, 0x16, 0x50, 0x16,
12425 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
12426 0x05, 0xf0, 0x09, 0xf0,
12427 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
12428 0x9c, 0x00, 0xa4, 0x00,
12429 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
12430 0xe9, 0x09, 0x5c, 0x0c,
12431 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
12432 0x42, 0x1d, 0x08, 0x44,
12433 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
12434 0x83, 0x55, 0x83, 0x59,
12435 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
12436 0x4b, 0xf4, 0x04, 0xf8,
12437 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
12438 0xa8, 0x00, 0xaa, 0x00,
12439 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
12440 0x7a, 0x01, 0x82, 0x01,
12441 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
12442 0x68, 0x08, 0x10, 0x0d,
12443 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
12444 0xf3, 0x10, 0x06, 0x12,
12445 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
12446 0xf0, 0x35, 0x05, 0xfe,
12447 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
12448 0xfe, 0x88, 0x01, 0xff,
12449 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12450 0x00, 0xfe, 0x57, 0x24,
12451 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
12452 0x00, 0x00, 0xff, 0x08,
12453 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12454 0xff, 0xff, 0xff, 0x13,
12455 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12456 0xfe, 0x04, 0xf7, 0xe8,
12457 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
12458 0x0d, 0x51, 0x37, 0xfe,
12459 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
12460 0xfe, 0xf8, 0x01, 0xfe,
12461 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
12462 0x05, 0xfe, 0x08, 0x0f,
12463 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
12464 0x28, 0x1c, 0x03, 0xfe,
12465 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
12466 0x48, 0xf0, 0xfe, 0x90,
12467 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
12468 0x02, 0xfe, 0x46, 0xf0,
12469 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
12470 0xfe, 0x4e, 0x02, 0xfe,
12471 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
12472 0x0d, 0xa2, 0x1c, 0x07,
12473 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
12474 0x1c, 0xf5, 0xfe, 0x1e,
12475 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
12476 0xde, 0x0a, 0x81, 0x01,
12477 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
12478 0x81, 0x01, 0x5c, 0xfe,
12479 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
12480 0xfe, 0x58, 0x1c, 0x1c,
12481 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
12482 0x2b, 0xfe, 0x9e, 0x02,
12483 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
12484 0x00, 0x47, 0xb8, 0x01,
12485 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
12486 0x1a, 0x31, 0xfe, 0x69,
12487 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
12488 0x1e, 0x1e, 0x20, 0x2c,
12489 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
12490 0x44, 0x15, 0x56, 0x51,
12491 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
12492 0x01, 0x18, 0x09, 0x00,
12493 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
12494 0x18, 0xfe, 0xc8, 0x54,
12495 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
12496 0xfe, 0x02, 0xe8, 0x30,
12497 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
12498 0xfe, 0xe4, 0x01, 0xfe,
12499 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
12500 0x26, 0xf0, 0xfe, 0x66,
12501 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
12502 0xef, 0x10, 0xfe, 0x9f,
12503 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
12504 0x70, 0x37, 0xfe, 0x48,
12505 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
12506 0x21, 0xb9, 0xc7, 0x20,
12507 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
12508 0xe1, 0x2a, 0xeb, 0xfe,
12509 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
12510 0x15, 0xfe, 0xe4, 0x00,
12511 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
12512 0xfe, 0x06, 0xf0, 0xfe,
12513 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
12514 0x03, 0x81, 0x1e, 0x1b,
12515 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
12516 0xea, 0xfe, 0x46, 0x1c,
12517 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12518 0xfe, 0x48, 0x1c, 0x75,
12519 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
12520 0xe1, 0x01, 0x18, 0x77,
12521 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
12522 0x8f, 0xfe, 0x70, 0x02,
12523 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
12524 0x16, 0xfe, 0x4a, 0x04,
12525 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
12526 0x02, 0x00, 0x10, 0x01,
12527 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
12528 0xee, 0xfe, 0x4c, 0x44,
12529 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
12530 0x7b, 0xec, 0x60, 0x8d,
12531 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
12532 0x0c, 0x06, 0x28, 0xfe,
12533 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
12534 0x13, 0x34, 0xfe, 0x4c,
12535 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
12536 0x13, 0x01, 0x0c, 0x06,
12537 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
12538 0x28, 0xf9, 0x1f, 0x7f,
12539 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
12540 0xfe, 0xa4, 0x0e, 0x05,
12541 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
12542 0x9c, 0x93, 0x3a, 0x0b,
12543 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
12544 0x7d, 0x1d, 0xfe, 0x46,
12545 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
12546 0xfe, 0x87, 0x83, 0xfe,
12547 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
12548 0x13, 0x0f, 0xfe, 0x20,
12549 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
12550 0x12, 0x01, 0x38, 0x06,
12551 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
12552 0x05, 0xd0, 0x54, 0x01,
12553 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
12554 0x50, 0x12, 0x5e, 0xff,
12555 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
12556 0x00, 0x10, 0x2f, 0xfe,
12557 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
12558 0x38, 0xfe, 0x4a, 0xf0,
12559 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
12560 0x21, 0x00, 0xf1, 0x2e,
12561 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
12562 0x10, 0x2f, 0xfe, 0xd0,
12563 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
12564 0x1c, 0x00, 0x4d, 0x01,
12565 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
12566 0x28, 0xfe, 0x24, 0x12,
12567 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
12568 0x0d, 0x00, 0x01, 0x42,
12569 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
12570 0x03, 0xb6, 0x1e, 0xfe,
12571 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
12572 0xfe, 0x72, 0x06, 0x0a,
12573 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
12574 0x19, 0x16, 0xfe, 0x68,
12575 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
12576 0x03, 0x9a, 0x1e, 0xfe,
12577 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
12578 0x48, 0xfe, 0x92, 0x06,
12579 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
12580 0x58, 0xff, 0x02, 0x00,
12581 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
12582 0xfe, 0xea, 0x06, 0x01,
12583 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
12584 0xfe, 0xe0, 0x06, 0x15,
12585 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
12586 0x01, 0x84, 0xfe, 0xae,
12587 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
12588 0x1e, 0xfe, 0x1a, 0x12,
12589 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
12590 0x43, 0x48, 0x62, 0x80,
12591 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
12592 0x36, 0xfe, 0x02, 0xf6,
12593 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
12594 0xd0, 0x0d, 0x17, 0xfe,
12595 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
12596 0x9e, 0x15, 0x82, 0x01,
12597 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
12598 0x57, 0x10, 0xe6, 0x05,
12599 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
12600 0xfe, 0x9c, 0x32, 0x5f,
12601 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
12602 0xfe, 0x0a, 0xf0, 0xfe,
12603 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
12604 0xaf, 0xa0, 0x05, 0x29,
12605 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
12606 0x00, 0x01, 0x08, 0x14,
12607 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
12608 0x14, 0x00, 0x05, 0xfe,
12609 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
12610 0x12, 0xfe, 0x30, 0x13,
12611 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
12612 0x01, 0x08, 0x14, 0x00,
12613 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
12614 0x78, 0x4f, 0x0f, 0xfe,
12615 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
12616 0x28, 0x48, 0xfe, 0x6c,
12617 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
12618 0x12, 0x53, 0x63, 0x4e,
12619 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
12620 0x6c, 0x08, 0xaf, 0xa0,
12621 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
12622 0x05, 0xed, 0xfe, 0x9c,
12623 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
12624 0x1e, 0xfe, 0x99, 0x58,
12625 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
12626 0x22, 0x6b, 0x01, 0x0c,
12627 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
12628 0x1e, 0x47, 0x2c, 0x7a,
12629 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
12630 0x01, 0x0c, 0x61, 0x65,
12631 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
12632 0x16, 0xfe, 0x08, 0x50,
12633 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
12634 0x01, 0xfe, 0xce, 0x1e,
12635 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
12636 0x01, 0xfe, 0xfe, 0x1e,
12637 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
12638 0x10, 0x01, 0x0c, 0x06,
12639 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
12640 0x10, 0x6a, 0x22, 0x6b,
12641 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
12642 0xfe, 0x9f, 0x83, 0x33,
12643 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
12644 0x3a, 0x0b, 0xfe, 0xc6,
12645 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
12646 0x01, 0xfe, 0xce, 0x1e,
12647 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
12648 0x04, 0xfe, 0xc0, 0x93,
12649 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
12650 0x10, 0x4b, 0x22, 0x4c,
12651 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
12652 0x4e, 0x11, 0x2f, 0xfe,
12653 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
12654 0x3c, 0x37, 0x88, 0xf5,
12655 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
12656 0xd3, 0xfe, 0x42, 0x0a,
12657 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
12658 0x05, 0x29, 0x01, 0x41,
12659 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
12660 0xfe, 0x14, 0x12, 0x01,
12661 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
12662 0x2e, 0x1c, 0x05, 0xfe,
12663 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
12664 0xfe, 0x2c, 0x1c, 0xfe,
12665 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
12666 0x92, 0x10, 0xc4, 0xf6,
12667 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
12668 0xe7, 0x10, 0xfe, 0x2b,
12669 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
12670 0xac, 0xfe, 0xd2, 0xf0,
12671 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
12672 0x1b, 0xbf, 0xd4, 0x5b,
12673 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
12674 0x5e, 0x32, 0x1f, 0x7f,
12675 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
12676 0x05, 0x70, 0xfe, 0x74,
12677 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
12678 0x0f, 0x4d, 0x01, 0xfe,
12679 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
12680 0x0d, 0x2b, 0xfe, 0xe2,
12681 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
12682 0xfe, 0x88, 0x13, 0x21,
12683 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
12684 0x83, 0x83, 0xfe, 0xc9,
12685 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
12686 0x91, 0x04, 0xfe, 0x84,
12687 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
12688 0xfe, 0xcb, 0x57, 0x0b,
12689 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
12690 0x6a, 0x3b, 0x6b, 0x10,
12691 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
12692 0x20, 0x6e, 0xdb, 0x64,
12693 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
12694 0xfe, 0x04, 0xfa, 0x64,
12695 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
12696 0x10, 0x98, 0x91, 0x6c,
12697 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
12698 0x4b, 0x7e, 0x4c, 0x01,
12699 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
12700 0x58, 0xfe, 0x91, 0x58,
12701 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
12702 0x1b, 0x40, 0x01, 0x0c,
12703 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
12704 0xfe, 0x10, 0x90, 0x04,
12705 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
12706 0x79, 0x0b, 0x0e, 0xfe,
12707 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
12708 0x01, 0x0c, 0x06, 0x0d,
12709 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
12710 0x0c, 0x58, 0xfe, 0x8d,
12711 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
12712 0x83, 0x33, 0x0b, 0x0e,
12713 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
12714 0x19, 0xfe, 0x19, 0x41,
12715 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
12716 0x19, 0xfe, 0x44, 0x00,
12717 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
12718 0x4c, 0xfe, 0x0c, 0x51,
12719 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
12720 0x76, 0x10, 0xac, 0xfe,
12721 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
12722 0xe3, 0x23, 0x07, 0xfe,
12723 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
12724 0xcc, 0x0c, 0x1f, 0x92,
12725 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
12726 0x0c, 0xfe, 0x3e, 0x10,
12727 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
12728 0xfe, 0xcb, 0xf0, 0xfe,
12729 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
12730 0xf4, 0x0c, 0x19, 0x94,
12731 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
12732 0xfe, 0xcc, 0xf0, 0xef,
12733 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
12734 0x4e, 0x11, 0x2f, 0xfe,
12735 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
12736 0x3c, 0x37, 0x88, 0xf5,
12737 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
12738 0x2f, 0xfe, 0x3e, 0x0d,
12739 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
12740 0xd2, 0x9f, 0xd3, 0x9f,
12741 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
12742 0xc5, 0x75, 0xd7, 0x99,
12743 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
12744 0x9c, 0x2f, 0xfe, 0x8c,
12745 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
12746 0x42, 0x00, 0x05, 0x70,
12747 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
12748 0x0d, 0xfe, 0x44, 0x13,
12749 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
12750 0xfe, 0xda, 0x0e, 0x0a,
12751 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
12752 0x10, 0x01, 0xfe, 0xf4,
12753 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
12754 0x15, 0x56, 0x01, 0x85,
12755 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
12756 0xcc, 0x10, 0x01, 0xa7,
12757 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
12758 0xfe, 0x99, 0x83, 0xfe,
12759 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
12760 0x43, 0x00, 0xfe, 0xa2,
12761 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
12762 0x00, 0x1d, 0x40, 0x15,
12763 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
12764 0xfe, 0x3a, 0x03, 0x01,
12765 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
12766 0x76, 0x06, 0x12, 0xfe,
12767 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
12768 0xfe, 0x9d, 0xf0, 0xfe,
12769 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
12770 0x0c, 0x61, 0x12, 0x44,
12771 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
12772 0xfe, 0x2e, 0x10, 0x19,
12773 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
12774 0xfe, 0x41, 0x00, 0xa2,
12775 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
12776 0xea, 0x4f, 0xfe, 0x04,
12777 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
12778 0x35, 0xfe, 0x12, 0x1c,
12779 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
12780 0xfe, 0xd4, 0x11, 0x05,
12781 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
12782 0xce, 0x45, 0x31, 0x51,
12783 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
12784 0x67, 0xfe, 0x98, 0x56,
12785 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
12786 0x0c, 0x06, 0x28, 0xfe,
12787 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
12788 0xfe, 0xfa, 0x14, 0xfe,
12789 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
12790 0xfe, 0xe0, 0x14, 0xfe,
12791 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
12792 0xfe, 0xad, 0x13, 0x05,
12793 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
12794 0xe7, 0xfe, 0x08, 0x1c,
12795 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
12796 0x48, 0x55, 0xa5, 0x3b,
12797 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
12798 0xf0, 0x1a, 0x03, 0xfe,
12799 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
12800 0xec, 0xe7, 0x53, 0x00,
12801 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
12802 0x01, 0xfe, 0x62, 0x1b,
12803 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
12804 0xea, 0xe7, 0x53, 0x92,
12805 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
12806 0xfe, 0x38, 0x01, 0x23,
12807 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
12808 0x01, 0x01, 0xfe, 0x1e,
12809 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
12810 0x26, 0x02, 0x21, 0x96,
12811 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
12812 0xc3, 0xfe, 0xe1, 0x10,
12813 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
12814 0xfe, 0x03, 0xdc, 0xfe,
12815 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
12816 0x00, 0xcc, 0x02, 0xfe,
12817 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
12818 0x0f, 0xfe, 0x1c, 0x80,
12819 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
12820 0x0f, 0xfe, 0x1e, 0x80,
12821 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
12822 0x1d, 0x80, 0x04, 0xfe,
12823 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
12824 0x1e, 0xac, 0xfe, 0x14,
12825 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
12826 0x1f, 0xfe, 0x30, 0xf4,
12827 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
12828 0x56, 0xfb, 0x01, 0xfe,
12829 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
12830 0xfe, 0x00, 0x1d, 0x15,
12831 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
12832 0x22, 0x1b, 0xfe, 0x1e,
12833 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
12834 0x96, 0x90, 0x04, 0xfe,
12835 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
12836 0x01, 0x01, 0x0c, 0x06,
12837 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
12838 0x0e, 0x77, 0xfe, 0x01,
12839 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
12840 0x21, 0x2c, 0xfe, 0x00,
12841 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
12842 0x06, 0x58, 0x03, 0xfe,
12843 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
12844 0x03, 0xfe, 0xb2, 0x00,
12845 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
12846 0x66, 0x10, 0x55, 0x10,
12847 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
12848 0x54, 0x2b, 0xfe, 0x88,
12849 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
12850 0x91, 0x54, 0x2b, 0xfe,
12851 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
12852 0x00, 0x40, 0x8d, 0x2c,
12853 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
12854 0x12, 0x1c, 0x75, 0xfe,
12855 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
12856 0x14, 0xfe, 0x0e, 0x47,
12857 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
12858 0xa7, 0x90, 0x34, 0x60,
12859 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
12860 0x09, 0x56, 0xfe, 0x34,
12861 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
12862 0xfe, 0x45, 0x48, 0x01,
12863 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
12864 0x09, 0x1a, 0xa5, 0x0a,
12865 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
12866 0xfe, 0x14, 0x56, 0xfe,
12867 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
12868 0xec, 0xb8, 0xfe, 0x9e,
12869 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
12870 0xf4, 0xfe, 0xdd, 0x10,
12871 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
12872 0x12, 0x09, 0x0d, 0xfe,
12873 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
12874 0x13, 0x09, 0xfe, 0x23,
12875 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
12876 0x24, 0xfe, 0x12, 0x12,
12877 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
12878 0xae, 0x41, 0x02, 0x32,
12879 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
12880 0x35, 0x32, 0x01, 0x43,
12881 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
12882 0x13, 0x01, 0x0c, 0x06,
12883 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
12884 0xe5, 0x55, 0xb0, 0xfe,
12885 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
12886 0xfe, 0xb6, 0x0e, 0x10,
12887 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
12888 0x88, 0x20, 0x6e, 0x01,
12889 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
12890 0x55, 0xfe, 0x04, 0xfa,
12891 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
12892 0xfe, 0x40, 0x56, 0xfe,
12893 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
12894 0x44, 0x55, 0xfe, 0xe5,
12895 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
12896 0x68, 0x22, 0x69, 0x01,
12897 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
12898 0x6b, 0xfe, 0x2c, 0x50,
12899 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
12900 0x50, 0x03, 0x68, 0x3b,
12901 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
12902 0x40, 0x50, 0xfe, 0xc2,
12903 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
12904 0x16, 0x3d, 0x27, 0x25,
12905 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
12906 0xa6, 0x23, 0x3f, 0x1b,
12907 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
12908 0xfe, 0x0a, 0x55, 0x31,
12909 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
12910 0x51, 0x05, 0x72, 0x01,
12911 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
12912 0x2a, 0x3c, 0x16, 0xc0,
12913 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
12914 0xfe, 0x66, 0x15, 0x05,
12915 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
12916 0x2b, 0x3d, 0x01, 0x08,
12917 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
12918 0xb6, 0x1e, 0x83, 0x01,
12919 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
12920 0x07, 0x90, 0x3f, 0x01,
12921 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
12922 0x01, 0x43, 0x09, 0x82,
12923 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
12924 0x05, 0x72, 0xfe, 0xc0,
12925 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
12926 0x32, 0x01, 0x08, 0x17,
12927 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
12928 0x3d, 0x27, 0x25, 0xbd,
12929 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
12930 0xe8, 0x14, 0x01, 0xa6,
12931 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
12932 0x0e, 0x12, 0x01, 0x43,
12933 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
12934 0x01, 0x08, 0x17, 0x73,
12935 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
12936 0x27, 0x25, 0xbd, 0x09,
12937 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
12938 0xb6, 0x14, 0x86, 0xa8,
12939 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
12940 0x82, 0x4e, 0x05, 0x72,
12941 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
12942 0xfe, 0xc0, 0x19, 0x05,
12943 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
12944 0xcc, 0x01, 0x08, 0x26,
12945 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
12946 0xcc, 0x15, 0x5e, 0x32,
12947 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
12948 0xad, 0x23, 0xfe, 0xff,
12949 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
12950 0x00, 0x57, 0x52, 0xad,
12951 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
12952 0x02, 0x00, 0x57, 0x52,
12953 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
12954 0x02, 0x13, 0x58, 0xff,
12955 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
12956 0x5c, 0x0a, 0x55, 0x01,
12957 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
12958 0xff, 0x03, 0x00, 0x54,
12959 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
12960 0x7c, 0x3a, 0x0b, 0x0e,
12961 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
12962 0xfe, 0x1a, 0xf7, 0x00,
12963 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
12964 0xda, 0x6d, 0x02, 0xfe,
12965 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
12966 0x02, 0x01, 0xc6, 0xfe,
12967 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
12968 0x25, 0xbe, 0x01, 0x08,
12969 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
12970 0x03, 0x9a, 0x1e, 0xfe,
12971 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
12972 0x48, 0xfe, 0x08, 0x17,
12973 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
12974 0x17, 0x4d, 0x13, 0x07,
12975 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
12976 0xff, 0x02, 0x83, 0x55,
12977 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
12978 0x17, 0x1c, 0x63, 0x13,
12979 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
12980 0x00, 0xb0, 0xfe, 0x80,
12981 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
12982 0x53, 0x07, 0xfe, 0x60,
12983 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
12984 0x00, 0x1c, 0x95, 0x13,
12985 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
12986 0xfe, 0x43, 0xf4, 0x96,
12987 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
12988 0xf4, 0x94, 0xf6, 0x8b,
12989 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
12990 0xda, 0x17, 0x62, 0x49,
12991 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
12992 0x71, 0x50, 0x26, 0xfe,
12993 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
12994 0x58, 0x02, 0x50, 0x13,
12995 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
12996 0x25, 0xbe, 0xfe, 0x03,
12997 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
12998 0x0a, 0x01, 0x08, 0x16,
12999 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13000 0x01, 0x08, 0x16, 0xa9,
13001 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13002 0x08, 0x16, 0xa9, 0x27,
13003 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13004 0x01, 0x38, 0x06, 0x24,
13005 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13006 0x78, 0x03, 0x9a, 0x1e,
13007 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13008 0xfe, 0x40, 0x5a, 0x23,
13009 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13010 0x80, 0x48, 0xfe, 0xaa,
13011 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13012 0xfe, 0xac, 0x1d, 0xfe,
13013 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13014 0x43, 0x48, 0x2d, 0x93,
13015 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13016 0x36, 0xfe, 0x34, 0xf4,
13017 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13018 0x28, 0x10, 0xfe, 0xc0,
13019 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13020 0x18, 0x45, 0xfe, 0x1c,
13021 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13022 0x19, 0xfe, 0x04, 0xf4,
13023 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13024 0x21, 0xfe, 0x7f, 0x01,
13025 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13026 0x7e, 0x01, 0xfe, 0xc8,
13027 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13028 0x21, 0xfe, 0x81, 0x01,
13029 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13030 0x13, 0x0d, 0x02, 0x14,
13031 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13032 0xfe, 0x82, 0x19, 0x14,
13033 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13034 0x08, 0x02, 0x14, 0x07,
13035 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13036 0x01, 0x08, 0x17, 0xc1,
13037 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13038 0x08, 0x02, 0x50, 0x02,
13039 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13040 0x14, 0x12, 0x01, 0x08,
13041 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13042 0x08, 0x17, 0x74, 0xfe,
13043 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13044 0x74, 0x5f, 0xcc, 0x01,
13045 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13046 0xfe, 0x49, 0xf4, 0x00,
13047 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13048 0x02, 0x00, 0x10, 0x2f,
13049 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13050 0x16, 0xfe, 0x64, 0x1a,
13051 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13052 0x61, 0x07, 0x44, 0x02,
13053 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13054 0x13, 0x0a, 0x9d, 0x01,
13055 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13056 0xfe, 0x80, 0xe7, 0x1a,
13057 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13058 0x0a, 0x5a, 0x01, 0x18,
13059 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13060 0x7e, 0x1e, 0xfe, 0x80,
13061 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13062 0xfe, 0x80, 0x4c, 0x0a,
13063 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13064 0xfe, 0x19, 0xde, 0xfe,
13065 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13066 0x2a, 0x1c, 0xfa, 0xb3,
13067 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13068 0xf4, 0x1a, 0xfe, 0xfa,
13069 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13070 0xfe, 0x18, 0x58, 0x03,
13071 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13072 0xfe, 0x30, 0xf4, 0x07,
13073 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13074 0xf7, 0x24, 0xb1, 0xfe,
13075 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13076 0xfe, 0xba, 0x10, 0x1c,
13077 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13078 0x1d, 0xf7, 0x54, 0xb1,
13079 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13080 0xaf, 0x19, 0xfe, 0x98,
13081 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13082 0x1a, 0x87, 0x8b, 0x0f,
13083 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13084 0xfe, 0x32, 0x90, 0x04,
13085 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13086 0x7c, 0x12, 0xfe, 0x0f,
13087 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13088 0x31, 0x02, 0xc9, 0x2b,
13089 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13090 0x6a, 0xfe, 0x19, 0xfe,
13091 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13092 0x1b, 0xfe, 0x36, 0x14,
13093 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13094 0xfe, 0x80, 0xe7, 0x1a,
13095 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13096 0x30, 0xfe, 0x12, 0x45,
13097 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13098 0x39, 0xf0, 0x75, 0x26,
13099 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13100 0xe3, 0x23, 0x07, 0xfe,
13101 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13102 0x56, 0xfe, 0x3c, 0x13,
13103 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13104 0x01, 0x18, 0xcb, 0xfe,
13105 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13106 0xfe, 0x00, 0xcc, 0xcb,
13107 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13108 0xfe, 0x80, 0x4c, 0x01,
13109 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13110 0x12, 0xfe, 0x14, 0x56,
13111 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13112 0x0d, 0x19, 0xfe, 0x15,
13113 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13114 0x83, 0xfe, 0x18, 0x80,
13115 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13116 0x90, 0xfe, 0xba, 0x90,
13117 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13118 0x21, 0xb9, 0x88, 0x20,
13119 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13120 0x18, 0xfe, 0x49, 0x44,
13121 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13122 0x1a, 0xa4, 0x0a, 0x67,
13123 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13124 0x1d, 0x7b, 0xfe, 0x52,
13125 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13126 0x4e, 0xe4, 0xdd, 0x7b,
13127 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13128 0xfe, 0x4e, 0xe4, 0xfe,
13129 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13130 0xfe, 0x08, 0x10, 0x03,
13131 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13132 0x68, 0x54, 0xfe, 0xf1,
13133 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13134 0xfe, 0x1a, 0xf4, 0xfe,
13135 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13136 0x09, 0x92, 0xfe, 0x5a,
13137 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13138 0x5a, 0xf0, 0xfe, 0xc8,
13139 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13140 0x1a, 0x10, 0x09, 0x0d,
13141 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13142 0x1f, 0x93, 0x01, 0x42,
13143 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13144 0xfe, 0x14, 0xf0, 0x08,
13145 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13146 0xfe, 0x82, 0xf0, 0xfe,
13147 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13148 0x02, 0x0f, 0xfe, 0x18,
13149 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13150 0x80, 0x04, 0xfe, 0x82,
13151 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13152 0x83, 0x33, 0x0b, 0x0e,
13153 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13154 0x02, 0x0f, 0xfe, 0x04,
13155 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13156 0x80, 0x04, 0xfe, 0x80,
13157 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13158 0xfe, 0x99, 0x83, 0xfe,
13159 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13160 0x83, 0xfe, 0xce, 0x47,
13161 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13162 0x0b, 0x0e, 0x02, 0x0f,
13163 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13164 0xfe, 0x08, 0x90, 0x04,
13165 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13166 0xfe, 0x8a, 0x93, 0x79,
13167 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13168 0x0b, 0x0e, 0x02, 0x0f,
13169 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13170 0xfe, 0x3c, 0x90, 0x04,
13171 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13172 0x04, 0xfe, 0x83, 0x83,
13173 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013174};
13175
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013176static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13177static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013178
Linus Torvalds1da177e2005-04-16 15:20:36 -070013179/*
13180 * EEPROM Configuration.
13181 *
13182 * All drivers should use this structure to set the default EEPROM
13183 * configuration. The BIOS now uses this structure when it is built.
13184 * Additional structure information can be found in a_condor.h where
13185 * the structure is defined.
13186 *
13187 * The *_Field_IsChar structs are needed to correct for endianness.
13188 * These values are read from the board 16 bits at a time directly
13189 * into the structs. Because some fields are char, the values will be
13190 * in the wrong order. The *_Field_IsChar tells when to flip the
13191 * bytes. Data read and written to PCI memory is automatically swapped
13192 * on big-endian platforms so char fields read as words are actually being
13193 * unswapped on big-endian platforms.
13194 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013195static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013196 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13197 0x0000, /* cfg_msw */
13198 0xFFFF, /* disc_enable */
13199 0xFFFF, /* wdtr_able */
13200 0xFFFF, /* sdtr_able */
13201 0xFFFF, /* start_motor */
13202 0xFFFF, /* tagqng_able */
13203 0xFFFF, /* bios_scan */
13204 0, /* scam_tolerant */
13205 7, /* adapter_scsi_id */
13206 0, /* bios_boot_delay */
13207 3, /* scsi_reset_delay */
13208 0, /* bios_id_lun */
13209 0, /* termination */
13210 0, /* reserved1 */
13211 0xFFE7, /* bios_ctrl */
13212 0xFFFF, /* ultra_able */
13213 0, /* reserved2 */
13214 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13215 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13216 0, /* dvc_cntl */
13217 0, /* bug_fix */
13218 0, /* serial_number_word1 */
13219 0, /* serial_number_word2 */
13220 0, /* serial_number_word3 */
13221 0, /* check_sum */
13222 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13223 , /* oem_name[16] */
13224 0, /* dvc_err_code */
13225 0, /* adv_err_code */
13226 0, /* adv_err_addr */
13227 0, /* saved_dvc_err_code */
13228 0, /* saved_adv_err_code */
13229 0, /* saved_adv_err_addr */
13230 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013231};
13232
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013233static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013234 0, /* cfg_lsw */
13235 0, /* cfg_msw */
13236 0, /* -disc_enable */
13237 0, /* wdtr_able */
13238 0, /* sdtr_able */
13239 0, /* start_motor */
13240 0, /* tagqng_able */
13241 0, /* bios_scan */
13242 0, /* scam_tolerant */
13243 1, /* adapter_scsi_id */
13244 1, /* bios_boot_delay */
13245 1, /* scsi_reset_delay */
13246 1, /* bios_id_lun */
13247 1, /* termination */
13248 1, /* reserved1 */
13249 0, /* bios_ctrl */
13250 0, /* ultra_able */
13251 0, /* reserved2 */
13252 1, /* max_host_qng */
13253 1, /* max_dvc_qng */
13254 0, /* dvc_cntl */
13255 0, /* bug_fix */
13256 0, /* serial_number_word1 */
13257 0, /* serial_number_word2 */
13258 0, /* serial_number_word3 */
13259 0, /* check_sum */
13260 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13261 , /* oem_name[16] */
13262 0, /* dvc_err_code */
13263 0, /* adv_err_code */
13264 0, /* adv_err_addr */
13265 0, /* saved_dvc_err_code */
13266 0, /* saved_adv_err_code */
13267 0, /* saved_adv_err_addr */
13268 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013269};
13270
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013271static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013272 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13273 0x0000, /* 01 cfg_msw */
13274 0xFFFF, /* 02 disc_enable */
13275 0xFFFF, /* 03 wdtr_able */
13276 0x4444, /* 04 sdtr_speed1 */
13277 0xFFFF, /* 05 start_motor */
13278 0xFFFF, /* 06 tagqng_able */
13279 0xFFFF, /* 07 bios_scan */
13280 0, /* 08 scam_tolerant */
13281 7, /* 09 adapter_scsi_id */
13282 0, /* bios_boot_delay */
13283 3, /* 10 scsi_reset_delay */
13284 0, /* bios_id_lun */
13285 0, /* 11 termination_se */
13286 0, /* termination_lvd */
13287 0xFFE7, /* 12 bios_ctrl */
13288 0x4444, /* 13 sdtr_speed2 */
13289 0x4444, /* 14 sdtr_speed3 */
13290 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13291 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13292 0, /* 16 dvc_cntl */
13293 0x4444, /* 17 sdtr_speed4 */
13294 0, /* 18 serial_number_word1 */
13295 0, /* 19 serial_number_word2 */
13296 0, /* 20 serial_number_word3 */
13297 0, /* 21 check_sum */
13298 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13299 , /* 22-29 oem_name[16] */
13300 0, /* 30 dvc_err_code */
13301 0, /* 31 adv_err_code */
13302 0, /* 32 adv_err_addr */
13303 0, /* 33 saved_dvc_err_code */
13304 0, /* 34 saved_adv_err_code */
13305 0, /* 35 saved_adv_err_addr */
13306 0, /* 36 reserved */
13307 0, /* 37 reserved */
13308 0, /* 38 reserved */
13309 0, /* 39 reserved */
13310 0, /* 40 reserved */
13311 0, /* 41 reserved */
13312 0, /* 42 reserved */
13313 0, /* 43 reserved */
13314 0, /* 44 reserved */
13315 0, /* 45 reserved */
13316 0, /* 46 reserved */
13317 0, /* 47 reserved */
13318 0, /* 48 reserved */
13319 0, /* 49 reserved */
13320 0, /* 50 reserved */
13321 0, /* 51 reserved */
13322 0, /* 52 reserved */
13323 0, /* 53 reserved */
13324 0, /* 54 reserved */
13325 0, /* 55 reserved */
13326 0, /* 56 cisptr_lsw */
13327 0, /* 57 cisprt_msw */
13328 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13329 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13330 0, /* 60 reserved */
13331 0, /* 61 reserved */
13332 0, /* 62 reserved */
13333 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013334};
13335
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013336static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013337 0, /* 00 cfg_lsw */
13338 0, /* 01 cfg_msw */
13339 0, /* 02 disc_enable */
13340 0, /* 03 wdtr_able */
13341 0, /* 04 sdtr_speed1 */
13342 0, /* 05 start_motor */
13343 0, /* 06 tagqng_able */
13344 0, /* 07 bios_scan */
13345 0, /* 08 scam_tolerant */
13346 1, /* 09 adapter_scsi_id */
13347 1, /* bios_boot_delay */
13348 1, /* 10 scsi_reset_delay */
13349 1, /* bios_id_lun */
13350 1, /* 11 termination_se */
13351 1, /* termination_lvd */
13352 0, /* 12 bios_ctrl */
13353 0, /* 13 sdtr_speed2 */
13354 0, /* 14 sdtr_speed3 */
13355 1, /* 15 max_host_qng */
13356 1, /* max_dvc_qng */
13357 0, /* 16 dvc_cntl */
13358 0, /* 17 sdtr_speed4 */
13359 0, /* 18 serial_number_word1 */
13360 0, /* 19 serial_number_word2 */
13361 0, /* 20 serial_number_word3 */
13362 0, /* 21 check_sum */
13363 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13364 , /* 22-29 oem_name[16] */
13365 0, /* 30 dvc_err_code */
13366 0, /* 31 adv_err_code */
13367 0, /* 32 adv_err_addr */
13368 0, /* 33 saved_dvc_err_code */
13369 0, /* 34 saved_adv_err_code */
13370 0, /* 35 saved_adv_err_addr */
13371 0, /* 36 reserved */
13372 0, /* 37 reserved */
13373 0, /* 38 reserved */
13374 0, /* 39 reserved */
13375 0, /* 40 reserved */
13376 0, /* 41 reserved */
13377 0, /* 42 reserved */
13378 0, /* 43 reserved */
13379 0, /* 44 reserved */
13380 0, /* 45 reserved */
13381 0, /* 46 reserved */
13382 0, /* 47 reserved */
13383 0, /* 48 reserved */
13384 0, /* 49 reserved */
13385 0, /* 50 reserved */
13386 0, /* 51 reserved */
13387 0, /* 52 reserved */
13388 0, /* 53 reserved */
13389 0, /* 54 reserved */
13390 0, /* 55 reserved */
13391 0, /* 56 cisptr_lsw */
13392 0, /* 57 cisprt_msw */
13393 0, /* 58 subsysvid */
13394 0, /* 59 subsysid */
13395 0, /* 60 reserved */
13396 0, /* 61 reserved */
13397 0, /* 62 reserved */
13398 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013399};
13400
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013401static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013402 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13403 0x0000, /* 01 cfg_msw */
13404 0xFFFF, /* 02 disc_enable */
13405 0xFFFF, /* 03 wdtr_able */
13406 0x5555, /* 04 sdtr_speed1 */
13407 0xFFFF, /* 05 start_motor */
13408 0xFFFF, /* 06 tagqng_able */
13409 0xFFFF, /* 07 bios_scan */
13410 0, /* 08 scam_tolerant */
13411 7, /* 09 adapter_scsi_id */
13412 0, /* bios_boot_delay */
13413 3, /* 10 scsi_reset_delay */
13414 0, /* bios_id_lun */
13415 0, /* 11 termination_se */
13416 0, /* termination_lvd */
13417 0xFFE7, /* 12 bios_ctrl */
13418 0x5555, /* 13 sdtr_speed2 */
13419 0x5555, /* 14 sdtr_speed3 */
13420 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13421 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13422 0, /* 16 dvc_cntl */
13423 0x5555, /* 17 sdtr_speed4 */
13424 0, /* 18 serial_number_word1 */
13425 0, /* 19 serial_number_word2 */
13426 0, /* 20 serial_number_word3 */
13427 0, /* 21 check_sum */
13428 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13429 , /* 22-29 oem_name[16] */
13430 0, /* 30 dvc_err_code */
13431 0, /* 31 adv_err_code */
13432 0, /* 32 adv_err_addr */
13433 0, /* 33 saved_dvc_err_code */
13434 0, /* 34 saved_adv_err_code */
13435 0, /* 35 saved_adv_err_addr */
13436 0, /* 36 reserved */
13437 0, /* 37 reserved */
13438 0, /* 38 reserved */
13439 0, /* 39 reserved */
13440 0, /* 40 reserved */
13441 0, /* 41 reserved */
13442 0, /* 42 reserved */
13443 0, /* 43 reserved */
13444 0, /* 44 reserved */
13445 0, /* 45 reserved */
13446 0, /* 46 reserved */
13447 0, /* 47 reserved */
13448 0, /* 48 reserved */
13449 0, /* 49 reserved */
13450 0, /* 50 reserved */
13451 0, /* 51 reserved */
13452 0, /* 52 reserved */
13453 0, /* 53 reserved */
13454 0, /* 54 reserved */
13455 0, /* 55 reserved */
13456 0, /* 56 cisptr_lsw */
13457 0, /* 57 cisprt_msw */
13458 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13459 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
13460 0, /* 60 reserved */
13461 0, /* 61 reserved */
13462 0, /* 62 reserved */
13463 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013464};
13465
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013466static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013467 0, /* 00 cfg_lsw */
13468 0, /* 01 cfg_msw */
13469 0, /* 02 disc_enable */
13470 0, /* 03 wdtr_able */
13471 0, /* 04 sdtr_speed1 */
13472 0, /* 05 start_motor */
13473 0, /* 06 tagqng_able */
13474 0, /* 07 bios_scan */
13475 0, /* 08 scam_tolerant */
13476 1, /* 09 adapter_scsi_id */
13477 1, /* bios_boot_delay */
13478 1, /* 10 scsi_reset_delay */
13479 1, /* bios_id_lun */
13480 1, /* 11 termination_se */
13481 1, /* termination_lvd */
13482 0, /* 12 bios_ctrl */
13483 0, /* 13 sdtr_speed2 */
13484 0, /* 14 sdtr_speed3 */
13485 1, /* 15 max_host_qng */
13486 1, /* max_dvc_qng */
13487 0, /* 16 dvc_cntl */
13488 0, /* 17 sdtr_speed4 */
13489 0, /* 18 serial_number_word1 */
13490 0, /* 19 serial_number_word2 */
13491 0, /* 20 serial_number_word3 */
13492 0, /* 21 check_sum */
13493 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13494 , /* 22-29 oem_name[16] */
13495 0, /* 30 dvc_err_code */
13496 0, /* 31 adv_err_code */
13497 0, /* 32 adv_err_addr */
13498 0, /* 33 saved_dvc_err_code */
13499 0, /* 34 saved_adv_err_code */
13500 0, /* 35 saved_adv_err_addr */
13501 0, /* 36 reserved */
13502 0, /* 37 reserved */
13503 0, /* 38 reserved */
13504 0, /* 39 reserved */
13505 0, /* 40 reserved */
13506 0, /* 41 reserved */
13507 0, /* 42 reserved */
13508 0, /* 43 reserved */
13509 0, /* 44 reserved */
13510 0, /* 45 reserved */
13511 0, /* 46 reserved */
13512 0, /* 47 reserved */
13513 0, /* 48 reserved */
13514 0, /* 49 reserved */
13515 0, /* 50 reserved */
13516 0, /* 51 reserved */
13517 0, /* 52 reserved */
13518 0, /* 53 reserved */
13519 0, /* 54 reserved */
13520 0, /* 55 reserved */
13521 0, /* 56 cisptr_lsw */
13522 0, /* 57 cisprt_msw */
13523 0, /* 58 subsysvid */
13524 0, /* 59 subsysid */
13525 0, /* 60 reserved */
13526 0, /* 61 reserved */
13527 0, /* 62 reserved */
13528 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013529};
13530
13531/*
13532 * Initialize the ADV_DVC_VAR structure.
13533 *
13534 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13535 *
13536 * For a non-fatal error return a warning code. If there are no warnings
13537 * then 0 is returned.
13538 */
Matthew Wilcox394dbf32007-07-26 11:56:40 -040013539static int __devinit
13540AdvInitGetConfig(struct pci_dev *pdev, ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013541{
Matthew Wilcox9649af32007-07-26 21:51:47 -060013542 unsigned short warn_code = 0;
13543 AdvPortAddr iop_base = asc_dvc->iop_base;
Matthew Wilcox9649af32007-07-26 21:51:47 -060013544 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013545 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013546
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013547 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013548
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013549 /*
13550 * Save the state of the PCI Configuration Command Register
13551 * "Parity Error Response Control" Bit. If the bit is clear (0),
13552 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
13553 * DMA parity errors.
13554 */
13555 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060013556 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
13557 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013558 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013559
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013560 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
13561 ADV_LIB_VERSION_MINOR;
13562 asc_dvc->cfg->chip_version =
13563 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013564
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013565 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
13566 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
13567 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013568
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013569 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
13570 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
13571 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013572
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013573 /*
13574 * Reset the chip to start and allow register writes.
13575 */
13576 if (AdvFindSignature(iop_base) == 0) {
13577 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
13578 return ADV_ERROR;
13579 } else {
13580 /*
13581 * The caller must set 'chip_type' to a valid setting.
13582 */
13583 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
13584 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
13585 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
13586 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13587 return ADV_ERROR;
13588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013589
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013590 /*
13591 * Reset Chip.
13592 */
13593 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13594 ADV_CTRL_REG_CMD_RESET);
13595 DvcSleepMilliSecond(100);
13596 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13597 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013598
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013599 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013600 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013601 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013602 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013603 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013604 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013605 }
13606 warn_code |= status;
13607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013608
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013609 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013610}
13611
13612/*
13613 * Initialize the ASC-3550.
13614 *
13615 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13616 *
13617 * For a non-fatal error return a warning code. If there are no warnings
13618 * then 0 is returned.
13619 *
13620 * Needed after initialization for error recovery.
13621 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013622static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013623{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013624 AdvPortAddr iop_base;
13625 ushort warn_code;
13626 ADV_DCNT sum;
13627 int begin_addr;
13628 int end_addr;
13629 ushort code_sum;
13630 int word;
13631 int j;
13632 int adv_asc3550_expanded_size;
13633 ADV_CARR_T *carrp;
13634 ADV_DCNT contig_len;
13635 ADV_SDCNT buf_size;
13636 ADV_PADDR carr_paddr;
13637 int i;
13638 ushort scsi_cfg1;
13639 uchar tid;
13640 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
13641 ushort wdtr_able = 0, sdtr_able, tagqng_able;
13642 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013643
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013644 /* If there is already an error, don't continue. */
13645 if (asc_dvc->err_code != 0) {
13646 return ADV_ERROR;
13647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013649 /*
13650 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
13651 */
13652 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
13653 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13654 return ADV_ERROR;
13655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013657 warn_code = 0;
13658 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013659
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013660 /*
13661 * Save the RISC memory BIOS region before writing the microcode.
13662 * The BIOS may already be loaded and using its RISC LRAM region
13663 * so its region must be saved and restored.
13664 *
13665 * Note: This code makes the assumption, which is currently true,
13666 * that a chip reset does not clear RISC LRAM.
13667 */
13668 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13669 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13670 bios_mem[i]);
13671 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013672
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013673 /*
13674 * Save current per TID negotiated values.
13675 */
13676 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
13677 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013678
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013679 bios_version =
13680 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
13681 major = (bios_version >> 12) & 0xF;
13682 minor = (bios_version >> 8) & 0xF;
13683 if (major < 3 || (major == 3 && minor == 1)) {
13684 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
13685 AdvReadWordLram(iop_base, 0x120, wdtr_able);
13686 } else {
13687 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13688 }
13689 }
13690 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13691 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13692 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13693 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13694 max_cmd[tid]);
13695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013696
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013697 /*
13698 * Load the Microcode
13699 *
13700 * Write the microcode image to RISC memory starting at address 0.
13701 */
13702 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
13703 /* Assume the following compressed format of the microcode buffer:
13704 *
13705 * 254 word (508 byte) table indexed by byte code followed
13706 * by the following byte codes:
13707 *
13708 * 1-Byte Code:
13709 * 00: Emit word 0 in table.
13710 * 01: Emit word 1 in table.
13711 * .
13712 * FD: Emit word 253 in table.
13713 *
13714 * Multi-Byte Code:
13715 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
13716 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
13717 */
13718 word = 0;
13719 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
13720 if (_adv_asc3550_buf[i] == 0xff) {
13721 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
13722 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13723 _adv_asc3550_buf
13724 [i +
13725 3] << 8) |
13726 _adv_asc3550_buf
13727 [i + 2]));
13728 word++;
13729 }
13730 i += 3;
13731 } else if (_adv_asc3550_buf[i] == 0xfe) {
13732 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13733 _adv_asc3550_buf[i +
13734 2]
13735 << 8) |
13736 _adv_asc3550_buf[i +
13737 1]));
13738 i += 2;
13739 word++;
13740 } else {
13741 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13742 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
13743 word++;
13744 }
13745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013746
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013747 /*
13748 * Set 'word' for later use to clear the rest of memory and save
13749 * the expanded mcode size.
13750 */
13751 word *= 2;
13752 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013753
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013754 /*
13755 * Clear the rest of ASC-3550 Internal RAM (8KB).
13756 */
13757 for (; word < ADV_3550_MEMSIZE; word += 2) {
13758 AdvWriteWordAutoIncLram(iop_base, 0);
13759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013760
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013761 /*
13762 * Verify the microcode checksum.
13763 */
13764 sum = 0;
13765 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013766
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013767 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
13768 sum += AdvReadWordAutoIncLram(iop_base);
13769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013770
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013771 if (sum != _adv_asc3550_chksum) {
13772 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
13773 return ADV_ERROR;
13774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013775
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013776 /*
13777 * Restore the RISC memory BIOS region.
13778 */
13779 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13780 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13781 bios_mem[i]);
13782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013783
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013784 /*
13785 * Calculate and write the microcode code checksum to the microcode
13786 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
13787 */
13788 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
13789 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
13790 code_sum = 0;
13791 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
13792 for (word = begin_addr; word < end_addr; word += 2) {
13793 code_sum += AdvReadWordAutoIncLram(iop_base);
13794 }
13795 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013796
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013797 /*
13798 * Read and save microcode version and date.
13799 */
13800 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
13801 asc_dvc->cfg->mcode_date);
13802 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
13803 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013804
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013805 /*
13806 * Set the chip type to indicate the ASC3550.
13807 */
13808 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013809
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013810 /*
13811 * If the PCI Configuration Command Register "Parity Error Response
13812 * Control" Bit was clear (0), then set the microcode variable
13813 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
13814 * to ignore DMA parity errors.
13815 */
13816 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
13817 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13818 word |= CONTROL_FLAG_IGNORE_PERR;
13819 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013821
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013822 /*
13823 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
13824 * threshold of 128 bytes. This register is only accessible to the host.
13825 */
13826 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
13827 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013828
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013829 /*
13830 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040013831 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013832 * device reports it is capable of in Inquiry byte 7.
13833 *
13834 * If SCSI Bus Resets have been disabled, then directly set
13835 * SDTR and WDTR from the EEPROM configuration. This will allow
13836 * the BIOS and warm boot to work without a SCSI bus hang on
13837 * the Inquiry caused by host and target mismatched DTR values.
13838 * Without the SCSI Bus Reset, before an Inquiry a device can't
13839 * be assumed to be in Asynchronous, Narrow mode.
13840 */
13841 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
13842 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
13843 asc_dvc->wdtr_able);
13844 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
13845 asc_dvc->sdtr_able);
13846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013847
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013848 /*
13849 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
13850 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
13851 * bitmask. These values determine the maximum SDTR speed negotiated
13852 * with a device.
13853 *
13854 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
13855 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
13856 * without determining here whether the device supports SDTR.
13857 *
13858 * 4-bit speed SDTR speed name
13859 * =========== ===============
13860 * 0000b (0x0) SDTR disabled
13861 * 0001b (0x1) 5 Mhz
13862 * 0010b (0x2) 10 Mhz
13863 * 0011b (0x3) 20 Mhz (Ultra)
13864 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
13865 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
13866 * 0110b (0x6) Undefined
13867 * .
13868 * 1111b (0xF) Undefined
13869 */
13870 word = 0;
13871 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13872 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
13873 /* Set Ultra speed for TID 'tid'. */
13874 word |= (0x3 << (4 * (tid % 4)));
13875 } else {
13876 /* Set Fast speed for TID 'tid'. */
13877 word |= (0x2 << (4 * (tid % 4)));
13878 }
13879 if (tid == 3) { /* Check if done with sdtr_speed1. */
13880 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
13881 word = 0;
13882 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
13883 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
13884 word = 0;
13885 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
13886 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
13887 word = 0;
13888 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
13889 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
13890 /* End of loop. */
13891 }
13892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013893
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013894 /*
13895 * Set microcode operating variable for the disconnect per TID bitmask.
13896 */
13897 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
13898 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013899
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013900 /*
13901 * Set SCSI_CFG0 Microcode Default Value.
13902 *
13903 * The microcode will set the SCSI_CFG0 register using this value
13904 * after it is started below.
13905 */
13906 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
13907 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
13908 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013909
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013910 /*
13911 * Determine SCSI_CFG1 Microcode Default Value.
13912 *
13913 * The microcode will set the SCSI_CFG1 register using this value
13914 * after it is started below.
13915 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013916
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013917 /* Read current SCSI_CFG1 Register value. */
13918 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013919
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013920 /*
13921 * If all three connectors are in use, return an error.
13922 */
13923 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
13924 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
13925 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
13926 return ADV_ERROR;
13927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013928
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013929 /*
13930 * If the internal narrow cable is reversed all of the SCSI_CTRL
13931 * register signals will be set. Check for and return an error if
13932 * this condition is found.
13933 */
13934 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
13935 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
13936 return ADV_ERROR;
13937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013938
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013939 /*
13940 * If this is a differential board and a single-ended device
13941 * is attached to one of the connectors, return an error.
13942 */
13943 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
13944 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
13945 return ADV_ERROR;
13946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013947
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013948 /*
13949 * If automatic termination control is enabled, then set the
13950 * termination value based on a table listed in a_condor.h.
13951 *
13952 * If manual termination was specified with an EEPROM setting
13953 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
13954 * is ready to be 'ored' into SCSI_CFG1.
13955 */
13956 if (asc_dvc->cfg->termination == 0) {
13957 /*
13958 * The software always controls termination by setting TERM_CTL_SEL.
13959 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
13960 */
13961 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013962
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013963 switch (scsi_cfg1 & CABLE_DETECT) {
13964 /* TERM_CTL_H: on, TERM_CTL_L: on */
13965 case 0x3:
13966 case 0x7:
13967 case 0xB:
13968 case 0xD:
13969 case 0xE:
13970 case 0xF:
13971 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
13972 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013973
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013974 /* TERM_CTL_H: on, TERM_CTL_L: off */
13975 case 0x1:
13976 case 0x5:
13977 case 0x9:
13978 case 0xA:
13979 case 0xC:
13980 asc_dvc->cfg->termination |= TERM_CTL_H;
13981 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013982
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013983 /* TERM_CTL_H: off, TERM_CTL_L: off */
13984 case 0x2:
13985 case 0x6:
13986 break;
13987 }
13988 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013989
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013990 /*
13991 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
13992 */
13993 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013994
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013995 /*
13996 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
13997 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
13998 * referenced, because the hardware internally inverts
13999 * the Termination High and Low bits if TERM_POL is set.
14000 */
14001 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014002
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014003 /*
14004 * Set SCSI_CFG1 Microcode Default Value
14005 *
14006 * Set filter value and possibly modified termination control
14007 * bits in the Microcode SCSI_CFG1 Register Value.
14008 *
14009 * The microcode will set the SCSI_CFG1 register using this value
14010 * after it is started below.
14011 */
14012 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14013 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014014
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014015 /*
14016 * Set MEM_CFG Microcode Default Value
14017 *
14018 * The microcode will set the MEM_CFG register using this value
14019 * after it is started below.
14020 *
14021 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14022 * are defined.
14023 *
14024 * ASC-3550 has 8KB internal memory.
14025 */
14026 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14027 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014028
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014029 /*
14030 * Set SEL_MASK Microcode Default Value
14031 *
14032 * The microcode will set the SEL_MASK register using this value
14033 * after it is started below.
14034 */
14035 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14036 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014037
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014038 /*
14039 * Build carrier freelist.
14040 *
14041 * Driver must have already allocated memory and set 'carrier_buf'.
14042 */
14043 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014044
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014045 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14046 asc_dvc->carr_freelist = NULL;
14047 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14048 buf_size = ADV_CARRIER_BUFSIZE;
14049 } else {
14050 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14051 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014052
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014053 do {
14054 /*
14055 * Get physical address of the carrier 'carrp'.
14056 */
14057 contig_len = sizeof(ADV_CARR_T);
14058 carr_paddr =
14059 cpu_to_le32(DvcGetPhyAddr
14060 (asc_dvc, NULL, (uchar *)carrp,
14061 (ADV_SDCNT *)&contig_len,
14062 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014063
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014064 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014065
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014066 /*
14067 * If the current carrier is not physically contiguous, then
14068 * maybe there was a page crossing. Try the next carrier aligned
14069 * start address.
14070 */
14071 if (contig_len < sizeof(ADV_CARR_T)) {
14072 carrp++;
14073 continue;
14074 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014075
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014076 carrp->carr_pa = carr_paddr;
14077 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014078
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014079 /*
14080 * Insert the carrier at the beginning of the freelist.
14081 */
14082 carrp->next_vpa =
14083 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14084 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014085
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014086 carrp++;
14087 }
14088 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014089
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014090 /*
14091 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14092 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014094 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14095 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14096 return ADV_ERROR;
14097 }
14098 asc_dvc->carr_freelist = (ADV_CARR_T *)
14099 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014100
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014101 /*
14102 * The first command issued will be placed in the stopper carrier.
14103 */
14104 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014105
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014106 /*
14107 * Set RISC ICQ physical address start value.
14108 */
14109 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014110
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014111 /*
14112 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14113 */
14114 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14115 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14116 return ADV_ERROR;
14117 }
14118 asc_dvc->carr_freelist = (ADV_CARR_T *)
14119 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014120
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014121 /*
14122 * The first command completed by the RISC will be placed in
14123 * the stopper.
14124 *
14125 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14126 * completed the RISC will set the ASC_RQ_STOPPER bit.
14127 */
14128 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014129
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014130 /*
14131 * Set RISC IRQ physical address start value.
14132 */
14133 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14134 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014135
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014136 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14137 (ADV_INTR_ENABLE_HOST_INTR |
14138 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014139
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014140 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14141 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014142
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014143 /* finally, finally, gentlemen, start your engine */
14144 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014145
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014146 /*
14147 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14148 * Resets should be performed. The RISC has to be running
14149 * to issue a SCSI Bus Reset.
14150 */
14151 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14152 /*
14153 * If the BIOS Signature is present in memory, restore the
14154 * BIOS Handshake Configuration Table and do not perform
14155 * a SCSI Bus Reset.
14156 */
14157 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14158 0x55AA) {
14159 /*
14160 * Restore per TID negotiated values.
14161 */
14162 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14163 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14164 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14165 tagqng_able);
14166 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14167 AdvWriteByteLram(iop_base,
14168 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14169 max_cmd[tid]);
14170 }
14171 } else {
14172 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14173 warn_code = ASC_WARN_BUSRESET_ERROR;
14174 }
14175 }
14176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014177
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014178 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014179}
14180
14181/*
14182 * Initialize the ASC-38C0800.
14183 *
14184 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14185 *
14186 * For a non-fatal error return a warning code. If there are no warnings
14187 * then 0 is returned.
14188 *
14189 * Needed after initialization for error recovery.
14190 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014191static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014192{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014193 AdvPortAddr iop_base;
14194 ushort warn_code;
14195 ADV_DCNT sum;
14196 int begin_addr;
14197 int end_addr;
14198 ushort code_sum;
14199 int word;
14200 int j;
14201 int adv_asc38C0800_expanded_size;
14202 ADV_CARR_T *carrp;
14203 ADV_DCNT contig_len;
14204 ADV_SDCNT buf_size;
14205 ADV_PADDR carr_paddr;
14206 int i;
14207 ushort scsi_cfg1;
14208 uchar byte;
14209 uchar tid;
14210 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14211 ushort wdtr_able, sdtr_able, tagqng_able;
14212 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014213
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014214 /* If there is already an error, don't continue. */
14215 if (asc_dvc->err_code != 0) {
14216 return ADV_ERROR;
14217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014218
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014219 /*
14220 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14221 */
14222 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14223 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14224 return ADV_ERROR;
14225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014226
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014227 warn_code = 0;
14228 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014229
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014230 /*
14231 * Save the RISC memory BIOS region before writing the microcode.
14232 * The BIOS may already be loaded and using its RISC LRAM region
14233 * so its region must be saved and restored.
14234 *
14235 * Note: This code makes the assumption, which is currently true,
14236 * that a chip reset does not clear RISC LRAM.
14237 */
14238 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14239 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14240 bios_mem[i]);
14241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014242
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014243 /*
14244 * Save current per TID negotiated values.
14245 */
14246 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14247 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14248 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14249 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14250 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14251 max_cmd[tid]);
14252 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014253
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014254 /*
14255 * RAM BIST (RAM Built-In Self Test)
14256 *
14257 * Address : I/O base + offset 0x38h register (byte).
14258 * Function: Bit 7-6(RW) : RAM mode
14259 * Normal Mode : 0x00
14260 * Pre-test Mode : 0x40
14261 * RAM Test Mode : 0x80
14262 * Bit 5 : unused
14263 * Bit 4(RO) : Done bit
14264 * Bit 3-0(RO) : Status
14265 * Host Error : 0x08
14266 * Int_RAM Error : 0x04
14267 * RISC Error : 0x02
14268 * SCSI Error : 0x01
14269 * No Error : 0x00
14270 *
14271 * Note: RAM BIST code should be put right here, before loading the
14272 * microcode and after saving the RISC memory BIOS region.
14273 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014274
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014275 /*
14276 * LRAM Pre-test
14277 *
14278 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14279 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14280 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14281 * to NORMAL_MODE, return an error too.
14282 */
14283 for (i = 0; i < 2; i++) {
14284 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14285 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14286 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14287 if ((byte & RAM_TEST_DONE) == 0
14288 || (byte & 0x0F) != PRE_TEST_VALUE) {
14289 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14290 return ADV_ERROR;
14291 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014292
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014293 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14294 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14295 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14296 != NORMAL_VALUE) {
14297 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14298 return ADV_ERROR;
14299 }
14300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014301
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014302 /*
14303 * LRAM Test - It takes about 1.5 ms to run through the test.
14304 *
14305 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14306 * If Done bit not set or Status not 0, save register byte, set the
14307 * err_code, and return an error.
14308 */
14309 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14310 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014311
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014312 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14313 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14314 /* Get here if Done bit not set or Status not 0. */
14315 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14316 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14317 return ADV_ERROR;
14318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014319
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014320 /* We need to reset back to normal mode after LRAM test passes. */
14321 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014322
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014323 /*
14324 * Load the Microcode
14325 *
14326 * Write the microcode image to RISC memory starting at address 0.
14327 *
14328 */
14329 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014330
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014331 /* Assume the following compressed format of the microcode buffer:
14332 *
14333 * 254 word (508 byte) table indexed by byte code followed
14334 * by the following byte codes:
14335 *
14336 * 1-Byte Code:
14337 * 00: Emit word 0 in table.
14338 * 01: Emit word 1 in table.
14339 * .
14340 * FD: Emit word 253 in table.
14341 *
14342 * Multi-Byte Code:
14343 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14344 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14345 */
14346 word = 0;
14347 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
14348 if (_adv_asc38C0800_buf[i] == 0xff) {
14349 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
14350 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14351 _adv_asc38C0800_buf
14352 [i +
14353 3] << 8) |
14354 _adv_asc38C0800_buf
14355 [i + 2]));
14356 word++;
14357 }
14358 i += 3;
14359 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
14360 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14361 _adv_asc38C0800_buf
14362 [i +
14363 2] << 8) |
14364 _adv_asc38C0800_buf[i
14365 +
14366 1]));
14367 i += 2;
14368 word++;
14369 } else {
14370 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14371 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
14372 word++;
14373 }
14374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014375
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014376 /*
14377 * Set 'word' for later use to clear the rest of memory and save
14378 * the expanded mcode size.
14379 */
14380 word *= 2;
14381 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014383 /*
14384 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
14385 */
14386 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
14387 AdvWriteWordAutoIncLram(iop_base, 0);
14388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014389
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014390 /*
14391 * Verify the microcode checksum.
14392 */
14393 sum = 0;
14394 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014395
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014396 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
14397 sum += AdvReadWordAutoIncLram(iop_base);
14398 }
14399 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014400
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014401 ASC_DBG2(1,
14402 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
14403 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014404
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014405 if (sum != _adv_asc38C0800_chksum) {
14406 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14407 return ADV_ERROR;
14408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014409
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014410 /*
14411 * Restore the RISC memory BIOS region.
14412 */
14413 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14414 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14415 bios_mem[i]);
14416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014417
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014418 /*
14419 * Calculate and write the microcode code checksum to the microcode
14420 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14421 */
14422 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14423 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14424 code_sum = 0;
14425 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14426 for (word = begin_addr; word < end_addr; word += 2) {
14427 code_sum += AdvReadWordAutoIncLram(iop_base);
14428 }
14429 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014430
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014431 /*
14432 * Read microcode version and date.
14433 */
14434 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14435 asc_dvc->cfg->mcode_date);
14436 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14437 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014438
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014439 /*
14440 * Set the chip type to indicate the ASC38C0800.
14441 */
14442 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014443
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014444 /*
14445 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
14446 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
14447 * cable detection and then we are able to read C_DET[3:0].
14448 *
14449 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
14450 * Microcode Default Value' section below.
14451 */
14452 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
14453 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
14454 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014455
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014456 /*
14457 * If the PCI Configuration Command Register "Parity Error Response
14458 * Control" Bit was clear (0), then set the microcode variable
14459 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14460 * to ignore DMA parity errors.
14461 */
14462 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14463 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14464 word |= CONTROL_FLAG_IGNORE_PERR;
14465 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014467
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014468 /*
14469 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
14470 * bits for the default FIFO threshold.
14471 *
14472 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
14473 *
14474 * For DMA Errata #4 set the BC_THRESH_ENB bit.
14475 */
14476 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14477 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
14478 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014479
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014480 /*
14481 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040014482 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014483 * device reports it is capable of in Inquiry byte 7.
14484 *
14485 * If SCSI Bus Resets have been disabled, then directly set
14486 * SDTR and WDTR from the EEPROM configuration. This will allow
14487 * the BIOS and warm boot to work without a SCSI bus hang on
14488 * the Inquiry caused by host and target mismatched DTR values.
14489 * Without the SCSI Bus Reset, before an Inquiry a device can't
14490 * be assumed to be in Asynchronous, Narrow mode.
14491 */
14492 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14493 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14494 asc_dvc->wdtr_able);
14495 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14496 asc_dvc->sdtr_able);
14497 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014498
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014499 /*
14500 * Set microcode operating variables for DISC and SDTR_SPEED1,
14501 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
14502 * configuration values.
14503 *
14504 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14505 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14506 * without determining here whether the device supports SDTR.
14507 */
14508 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14509 asc_dvc->cfg->disc_enable);
14510 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
14511 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
14512 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
14513 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014514
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014515 /*
14516 * Set SCSI_CFG0 Microcode Default Value.
14517 *
14518 * The microcode will set the SCSI_CFG0 register using this value
14519 * after it is started below.
14520 */
14521 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14522 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14523 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014524
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014525 /*
14526 * Determine SCSI_CFG1 Microcode Default Value.
14527 *
14528 * The microcode will set the SCSI_CFG1 register using this value
14529 * after it is started below.
14530 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014531
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014532 /* Read current SCSI_CFG1 Register value. */
14533 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014535 /*
14536 * If the internal narrow cable is reversed all of the SCSI_CTRL
14537 * register signals will be set. Check for and return an error if
14538 * this condition is found.
14539 */
14540 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14541 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14542 return ADV_ERROR;
14543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014544
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014545 /*
14546 * All kind of combinations of devices attached to one of four connectors
14547 * are acceptable except HVD device attached. For example, LVD device can
14548 * be attached to SE connector while SE device attached to LVD connector.
14549 * If LVD device attached to SE connector, it only runs up to Ultra speed.
14550 *
14551 * If an HVD device is attached to one of LVD connectors, return an error.
14552 * However, there is no way to detect HVD device attached to SE connectors.
14553 */
14554 if (scsi_cfg1 & HVD) {
14555 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
14556 return ADV_ERROR;
14557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014558
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014559 /*
14560 * If either SE or LVD automatic termination control is enabled, then
14561 * set the termination value based on a table listed in a_condor.h.
14562 *
14563 * If manual termination was specified with an EEPROM setting then
14564 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
14565 * be 'ored' into SCSI_CFG1.
14566 */
14567 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
14568 /* SE automatic termination control is enabled. */
14569 switch (scsi_cfg1 & C_DET_SE) {
14570 /* TERM_SE_HI: on, TERM_SE_LO: on */
14571 case 0x1:
14572 case 0x2:
14573 case 0x3:
14574 asc_dvc->cfg->termination |= TERM_SE;
14575 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014577 /* TERM_SE_HI: on, TERM_SE_LO: off */
14578 case 0x0:
14579 asc_dvc->cfg->termination |= TERM_SE_HI;
14580 break;
14581 }
14582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014583
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014584 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
14585 /* LVD automatic termination control is enabled. */
14586 switch (scsi_cfg1 & C_DET_LVD) {
14587 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
14588 case 0x4:
14589 case 0x8:
14590 case 0xC:
14591 asc_dvc->cfg->termination |= TERM_LVD;
14592 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014593
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014594 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
14595 case 0x0:
14596 break;
14597 }
14598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014599
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014600 /*
14601 * Clear any set TERM_SE and TERM_LVD bits.
14602 */
14603 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014604
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014605 /*
14606 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
14607 */
14608 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014609
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014610 /*
14611 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
14612 * and set possibly modified termination control bits in the Microcode
14613 * SCSI_CFG1 Register Value.
14614 */
14615 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014616
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014617 /*
14618 * Set SCSI_CFG1 Microcode Default Value
14619 *
14620 * Set possibly modified termination control and reset DIS_TERM_DRV
14621 * bits in the Microcode SCSI_CFG1 Register Value.
14622 *
14623 * The microcode will set the SCSI_CFG1 register using this value
14624 * after it is started below.
14625 */
14626 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014627
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014628 /*
14629 * Set MEM_CFG Microcode Default Value
14630 *
14631 * The microcode will set the MEM_CFG register using this value
14632 * after it is started below.
14633 *
14634 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14635 * are defined.
14636 *
14637 * ASC-38C0800 has 16KB internal memory.
14638 */
14639 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14640 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014641
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014642 /*
14643 * Set SEL_MASK Microcode Default Value
14644 *
14645 * The microcode will set the SEL_MASK register using this value
14646 * after it is started below.
14647 */
14648 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14649 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014650
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014651 /*
14652 * Build the carrier freelist.
14653 *
14654 * Driver must have already allocated memory and set 'carrier_buf'.
14655 */
14656 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014657
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014658 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14659 asc_dvc->carr_freelist = NULL;
14660 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14661 buf_size = ADV_CARRIER_BUFSIZE;
14662 } else {
14663 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014665
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014666 do {
14667 /*
14668 * Get physical address for the carrier 'carrp'.
14669 */
14670 contig_len = sizeof(ADV_CARR_T);
14671 carr_paddr =
14672 cpu_to_le32(DvcGetPhyAddr
14673 (asc_dvc, NULL, (uchar *)carrp,
14674 (ADV_SDCNT *)&contig_len,
14675 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014676
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014677 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014678
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014679 /*
14680 * If the current carrier is not physically contiguous, then
14681 * maybe there was a page crossing. Try the next carrier aligned
14682 * start address.
14683 */
14684 if (contig_len < sizeof(ADV_CARR_T)) {
14685 carrp++;
14686 continue;
14687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014688
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014689 carrp->carr_pa = carr_paddr;
14690 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014692 /*
14693 * Insert the carrier at the beginning of the freelist.
14694 */
14695 carrp->next_vpa =
14696 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14697 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014698
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014699 carrp++;
14700 }
14701 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014702
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014703 /*
14704 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14705 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014706
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014707 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14708 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14709 return ADV_ERROR;
14710 }
14711 asc_dvc->carr_freelist = (ADV_CARR_T *)
14712 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014713
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014714 /*
14715 * The first command issued will be placed in the stopper carrier.
14716 */
14717 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014718
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014719 /*
14720 * Set RISC ICQ physical address start value.
14721 * carr_pa is LE, must be native before write
14722 */
14723 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014724
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014725 /*
14726 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14727 */
14728 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14729 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14730 return ADV_ERROR;
14731 }
14732 asc_dvc->carr_freelist = (ADV_CARR_T *)
14733 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014734
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014735 /*
14736 * The first command completed by the RISC will be placed in
14737 * the stopper.
14738 *
14739 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14740 * completed the RISC will set the ASC_RQ_STOPPER bit.
14741 */
14742 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014743
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014744 /*
14745 * Set RISC IRQ physical address start value.
14746 *
14747 * carr_pa is LE, must be native before write *
14748 */
14749 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14750 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014751
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014752 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14753 (ADV_INTR_ENABLE_HOST_INTR |
14754 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014755
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014756 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14757 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014758
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014759 /* finally, finally, gentlemen, start your engine */
14760 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014761
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014762 /*
14763 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14764 * Resets should be performed. The RISC has to be running
14765 * to issue a SCSI Bus Reset.
14766 */
14767 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14768 /*
14769 * If the BIOS Signature is present in memory, restore the
14770 * BIOS Handshake Configuration Table and do not perform
14771 * a SCSI Bus Reset.
14772 */
14773 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14774 0x55AA) {
14775 /*
14776 * Restore per TID negotiated values.
14777 */
14778 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14779 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14780 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14781 tagqng_able);
14782 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14783 AdvWriteByteLram(iop_base,
14784 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14785 max_cmd[tid]);
14786 }
14787 } else {
14788 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14789 warn_code = ASC_WARN_BUSRESET_ERROR;
14790 }
14791 }
14792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014793
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014794 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014795}
14796
14797/*
14798 * Initialize the ASC-38C1600.
14799 *
14800 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
14801 *
14802 * For a non-fatal error return a warning code. If there are no warnings
14803 * then 0 is returned.
14804 *
14805 * Needed after initialization for error recovery.
14806 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014807static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014808{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014809 AdvPortAddr iop_base;
14810 ushort warn_code;
14811 ADV_DCNT sum;
14812 int begin_addr;
14813 int end_addr;
14814 ushort code_sum;
14815 long word;
14816 int j;
14817 int adv_asc38C1600_expanded_size;
14818 ADV_CARR_T *carrp;
14819 ADV_DCNT contig_len;
14820 ADV_SDCNT buf_size;
14821 ADV_PADDR carr_paddr;
14822 int i;
14823 ushort scsi_cfg1;
14824 uchar byte;
14825 uchar tid;
14826 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14827 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
14828 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014829
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014830 /* If there is already an error, don't continue. */
14831 if (asc_dvc->err_code != 0) {
14832 return ADV_ERROR;
14833 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014834
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014835 /*
14836 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
14837 */
14838 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
14839 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14840 return ADV_ERROR;
14841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014842
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014843 warn_code = 0;
14844 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014845
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014846 /*
14847 * Save the RISC memory BIOS region before writing the microcode.
14848 * The BIOS may already be loaded and using its RISC LRAM region
14849 * so its region must be saved and restored.
14850 *
14851 * Note: This code makes the assumption, which is currently true,
14852 * that a chip reset does not clear RISC LRAM.
14853 */
14854 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14855 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14856 bios_mem[i]);
14857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014858
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014859 /*
14860 * Save current per TID negotiated values.
14861 */
14862 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14863 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14864 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
14865 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14866 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
14867 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14868 max_cmd[tid]);
14869 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014870
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014871 /*
14872 * RAM BIST (Built-In Self Test)
14873 *
14874 * Address : I/O base + offset 0x38h register (byte).
14875 * Function: Bit 7-6(RW) : RAM mode
14876 * Normal Mode : 0x00
14877 * Pre-test Mode : 0x40
14878 * RAM Test Mode : 0x80
14879 * Bit 5 : unused
14880 * Bit 4(RO) : Done bit
14881 * Bit 3-0(RO) : Status
14882 * Host Error : 0x08
14883 * Int_RAM Error : 0x04
14884 * RISC Error : 0x02
14885 * SCSI Error : 0x01
14886 * No Error : 0x00
14887 *
14888 * Note: RAM BIST code should be put right here, before loading the
14889 * microcode and after saving the RISC memory BIOS region.
14890 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014891
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014892 /*
14893 * LRAM Pre-test
14894 *
14895 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14896 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14897 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14898 * to NORMAL_MODE, return an error too.
14899 */
14900 for (i = 0; i < 2; i++) {
14901 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14902 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14903 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14904 if ((byte & RAM_TEST_DONE) == 0
14905 || (byte & 0x0F) != PRE_TEST_VALUE) {
14906 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14907 return ADV_ERROR;
14908 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014909
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014910 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14911 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14912 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14913 != NORMAL_VALUE) {
14914 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14915 return ADV_ERROR;
14916 }
14917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014918
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014919 /*
14920 * LRAM Test - It takes about 1.5 ms to run through the test.
14921 *
14922 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14923 * If Done bit not set or Status not 0, save register byte, set the
14924 * err_code, and return an error.
14925 */
14926 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14927 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014928
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014929 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14930 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14931 /* Get here if Done bit not set or Status not 0. */
14932 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14933 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14934 return ADV_ERROR;
14935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014936
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014937 /* We need to reset back to normal mode after LRAM test passes. */
14938 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014939
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014940 /*
14941 * Load the Microcode
14942 *
14943 * Write the microcode image to RISC memory starting at address 0.
14944 *
14945 */
14946 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014947
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014948 /*
14949 * Assume the following compressed format of the microcode buffer:
14950 *
14951 * 254 word (508 byte) table indexed by byte code followed
14952 * by the following byte codes:
14953 *
14954 * 1-Byte Code:
14955 * 00: Emit word 0 in table.
14956 * 01: Emit word 1 in table.
14957 * .
14958 * FD: Emit word 253 in table.
14959 *
14960 * Multi-Byte Code:
14961 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14962 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14963 */
14964 word = 0;
14965 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
14966 if (_adv_asc38C1600_buf[i] == 0xff) {
14967 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
14968 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14969 _adv_asc38C1600_buf
14970 [i +
14971 3] << 8) |
14972 _adv_asc38C1600_buf
14973 [i + 2]));
14974 word++;
14975 }
14976 i += 3;
14977 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
14978 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14979 _adv_asc38C1600_buf
14980 [i +
14981 2] << 8) |
14982 _adv_asc38C1600_buf[i
14983 +
14984 1]));
14985 i += 2;
14986 word++;
14987 } else {
14988 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14989 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
14990 word++;
14991 }
14992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014993
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014994 /*
14995 * Set 'word' for later use to clear the rest of memory and save
14996 * the expanded mcode size.
14997 */
14998 word *= 2;
14999 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015000
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015001 /*
15002 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15003 */
15004 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15005 AdvWriteWordAutoIncLram(iop_base, 0);
15006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015007
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015008 /*
15009 * Verify the microcode checksum.
15010 */
15011 sum = 0;
15012 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015013
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015014 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15015 sum += AdvReadWordAutoIncLram(iop_base);
15016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015017
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015018 if (sum != _adv_asc38C1600_chksum) {
15019 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15020 return ADV_ERROR;
15021 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015022
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015023 /*
15024 * Restore the RISC memory BIOS region.
15025 */
15026 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15027 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15028 bios_mem[i]);
15029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015031 /*
15032 * Calculate and write the microcode code checksum to the microcode
15033 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15034 */
15035 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15036 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15037 code_sum = 0;
15038 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15039 for (word = begin_addr; word < end_addr; word += 2) {
15040 code_sum += AdvReadWordAutoIncLram(iop_base);
15041 }
15042 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015043
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015044 /*
15045 * Read microcode version and date.
15046 */
15047 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15048 asc_dvc->cfg->mcode_date);
15049 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15050 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015051
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015052 /*
15053 * Set the chip type to indicate the ASC38C1600.
15054 */
15055 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015056
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015057 /*
15058 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15059 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15060 * cable detection and then we are able to read C_DET[3:0].
15061 *
15062 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15063 * Microcode Default Value' section below.
15064 */
15065 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15066 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15067 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015068
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015069 /*
15070 * If the PCI Configuration Command Register "Parity Error Response
15071 * Control" Bit was clear (0), then set the microcode variable
15072 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15073 * to ignore DMA parity errors.
15074 */
15075 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15076 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15077 word |= CONTROL_FLAG_IGNORE_PERR;
15078 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015080
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015081 /*
15082 * If the BIOS control flag AIPP (Asynchronous Information
15083 * Phase Protection) disable bit is not set, then set the firmware
15084 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15085 * AIPP checking and encoding.
15086 */
15087 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15088 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15089 word |= CONTROL_FLAG_ENABLE_AIPP;
15090 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015092
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015093 /*
15094 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15095 * and START_CTL_TH [3:2].
15096 */
15097 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15098 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015099
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015100 /*
15101 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040015102 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015103 * device reports it is capable of in Inquiry byte 7.
15104 *
15105 * If SCSI Bus Resets have been disabled, then directly set
15106 * SDTR and WDTR from the EEPROM configuration. This will allow
15107 * the BIOS and warm boot to work without a SCSI bus hang on
15108 * the Inquiry caused by host and target mismatched DTR values.
15109 * Without the SCSI Bus Reset, before an Inquiry a device can't
15110 * be assumed to be in Asynchronous, Narrow mode.
15111 */
15112 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15113 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15114 asc_dvc->wdtr_able);
15115 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15116 asc_dvc->sdtr_able);
15117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015118
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015119 /*
15120 * Set microcode operating variables for DISC and SDTR_SPEED1,
15121 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15122 * configuration values.
15123 *
15124 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15125 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15126 * without determining here whether the device supports SDTR.
15127 */
15128 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15129 asc_dvc->cfg->disc_enable);
15130 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15131 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15132 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15133 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015135 /*
15136 * Set SCSI_CFG0 Microcode Default Value.
15137 *
15138 * The microcode will set the SCSI_CFG0 register using this value
15139 * after it is started below.
15140 */
15141 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15142 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15143 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015144
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015145 /*
15146 * Calculate SCSI_CFG1 Microcode Default Value.
15147 *
15148 * The microcode will set the SCSI_CFG1 register using this value
15149 * after it is started below.
15150 *
15151 * Each ASC-38C1600 function has only two cable detect bits.
15152 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15153 */
15154 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015155
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015156 /*
15157 * If the cable is reversed all of the SCSI_CTRL register signals
15158 * will be set. Check for and return an error if this condition is
15159 * found.
15160 */
15161 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15162 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15163 return ADV_ERROR;
15164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015165
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015166 /*
15167 * Each ASC-38C1600 function has two connectors. Only an HVD device
15168 * can not be connected to either connector. An LVD device or SE device
15169 * may be connected to either connecor. If an SE device is connected,
15170 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15171 *
15172 * If an HVD device is attached, return an error.
15173 */
15174 if (scsi_cfg1 & HVD) {
15175 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15176 return ADV_ERROR;
15177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015178
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015179 /*
15180 * Each function in the ASC-38C1600 uses only the SE cable detect and
15181 * termination because there are two connectors for each function. Each
15182 * function may use either LVD or SE mode. Corresponding the SE automatic
15183 * termination control EEPROM bits are used for each function. Each
15184 * function has its own EEPROM. If SE automatic control is enabled for
15185 * the function, then set the termination value based on a table listed
15186 * in a_condor.h.
15187 *
15188 * If manual termination is specified in the EEPROM for the function,
15189 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15190 * ready to be 'ored' into SCSI_CFG1.
15191 */
15192 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060015193 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015194 /* SE automatic termination control is enabled. */
15195 switch (scsi_cfg1 & C_DET_SE) {
15196 /* TERM_SE_HI: on, TERM_SE_LO: on */
15197 case 0x1:
15198 case 0x2:
15199 case 0x3:
15200 asc_dvc->cfg->termination |= TERM_SE;
15201 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015202
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015203 case 0x0:
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060015204 if (PCI_FUNC(pdev->devfn) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015205 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15206 } else {
15207 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15208 asc_dvc->cfg->termination |= TERM_SE_HI;
15209 }
15210 break;
15211 }
15212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015213
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015214 /*
15215 * Clear any set TERM_SE bits.
15216 */
15217 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015218
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015219 /*
15220 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15221 */
15222 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015223
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015224 /*
15225 * Clear Big Endian and Terminator Polarity bits and set possibly
15226 * modified termination control bits in the Microcode SCSI_CFG1
15227 * Register Value.
15228 *
15229 * Big Endian bit is not used even on big endian machines.
15230 */
15231 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015232
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015233 /*
15234 * Set SCSI_CFG1 Microcode Default Value
15235 *
15236 * Set possibly modified termination control bits in the Microcode
15237 * SCSI_CFG1 Register Value.
15238 *
15239 * The microcode will set the SCSI_CFG1 register using this value
15240 * after it is started below.
15241 */
15242 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015243
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015244 /*
15245 * Set MEM_CFG Microcode Default Value
15246 *
15247 * The microcode will set the MEM_CFG register using this value
15248 * after it is started below.
15249 *
15250 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15251 * are defined.
15252 *
15253 * ASC-38C1600 has 32KB internal memory.
15254 *
15255 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15256 * out a special 16K Adv Library and Microcode version. After the issue
15257 * resolved, we should turn back to the 32K support. Both a_condor.h and
15258 * mcode.sas files also need to be updated.
15259 *
15260 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15261 * BIOS_EN | RAM_SZ_32KB);
15262 */
15263 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15264 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015265
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015266 /*
15267 * Set SEL_MASK Microcode Default Value
15268 *
15269 * The microcode will set the SEL_MASK register using this value
15270 * after it is started below.
15271 */
15272 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15273 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015274
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015275 /*
15276 * Build the carrier freelist.
15277 *
15278 * Driver must have already allocated memory and set 'carrier_buf'.
15279 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015280
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015281 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015283 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15284 asc_dvc->carr_freelist = NULL;
15285 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15286 buf_size = ADV_CARRIER_BUFSIZE;
15287 } else {
15288 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015290
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015291 do {
15292 /*
15293 * Get physical address for the carrier 'carrp'.
15294 */
15295 contig_len = sizeof(ADV_CARR_T);
15296 carr_paddr =
15297 cpu_to_le32(DvcGetPhyAddr
15298 (asc_dvc, NULL, (uchar *)carrp,
15299 (ADV_SDCNT *)&contig_len,
15300 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015301
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015302 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015303
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015304 /*
15305 * If the current carrier is not physically contiguous, then
15306 * maybe there was a page crossing. Try the next carrier aligned
15307 * start address.
15308 */
15309 if (contig_len < sizeof(ADV_CARR_T)) {
15310 carrp++;
15311 continue;
15312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015313
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015314 carrp->carr_pa = carr_paddr;
15315 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015316
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015317 /*
15318 * Insert the carrier at the beginning of the freelist.
15319 */
15320 carrp->next_vpa =
15321 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15322 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015323
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015324 carrp++;
15325 }
15326 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015327
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015328 /*
15329 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15330 */
15331 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15332 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15333 return ADV_ERROR;
15334 }
15335 asc_dvc->carr_freelist = (ADV_CARR_T *)
15336 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015337
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015338 /*
15339 * The first command issued will be placed in the stopper carrier.
15340 */
15341 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015342
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015343 /*
15344 * Set RISC ICQ physical address start value. Initialize the
15345 * COMMA register to the same value otherwise the RISC will
15346 * prematurely detect a command is available.
15347 */
15348 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
15349 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
15350 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015351
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015352 /*
15353 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15354 */
15355 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15356 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15357 return ADV_ERROR;
15358 }
15359 asc_dvc->carr_freelist = (ADV_CARR_T *)
15360 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015361
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015362 /*
15363 * The first command completed by the RISC will be placed in
15364 * the stopper.
15365 *
15366 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15367 * completed the RISC will set the ASC_RQ_STOPPER bit.
15368 */
15369 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015370
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015371 /*
15372 * Set RISC IRQ physical address start value.
15373 */
15374 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15375 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015376
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015377 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15378 (ADV_INTR_ENABLE_HOST_INTR |
15379 ADV_INTR_ENABLE_GLOBAL_INTR));
15380 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15381 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015383 /* finally, finally, gentlemen, start your engine */
15384 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015385
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015386 /*
15387 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15388 * Resets should be performed. The RISC has to be running
15389 * to issue a SCSI Bus Reset.
15390 */
15391 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15392 /*
15393 * If the BIOS Signature is present in memory, restore the
15394 * per TID microcode operating variables.
15395 */
15396 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15397 0x55AA) {
15398 /*
15399 * Restore per TID negotiated values.
15400 */
15401 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15402 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15403 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15404 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15405 tagqng_able);
15406 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15407 AdvWriteByteLram(iop_base,
15408 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15409 max_cmd[tid]);
15410 }
15411 } else {
15412 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15413 warn_code = ASC_WARN_BUSRESET_ERROR;
15414 }
15415 }
15416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015417
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015418 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015419}
15420
15421/*
15422 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15423 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15424 * all of this is done.
15425 *
15426 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15427 *
15428 * For a non-fatal error return a warning code. If there are no warnings
15429 * then 0 is returned.
15430 *
15431 * Note: Chip is stopped on entry.
15432 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015433static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015434{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015435 AdvPortAddr iop_base;
15436 ushort warn_code;
15437 ADVEEP_3550_CONFIG eep_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015438
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015439 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015441 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015442
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015443 /*
15444 * Read the board's EEPROM configuration.
15445 *
15446 * Set default values if a bad checksum is found.
15447 */
15448 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
15449 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015450
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015451 /*
15452 * Set EEPROM default values.
15453 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040015454 memcpy(&eep_config, &Default_3550_EEPROM_Config,
15455 sizeof(ADVEEP_3550_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015456
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015457 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040015458 * Assume the 6 byte board serial number that was read from
15459 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015460 */
15461 eep_config.serial_number_word3 =
15462 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015463
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015464 eep_config.serial_number_word2 =
15465 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015466
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015467 eep_config.serial_number_word1 =
15468 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015469
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015470 AdvSet3550EEPConfig(iop_base, &eep_config);
15471 }
15472 /*
15473 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15474 * EEPROM configuration that was read.
15475 *
15476 * This is the mapping of EEPROM fields to Adv Library fields.
15477 */
15478 asc_dvc->wdtr_able = eep_config.wdtr_able;
15479 asc_dvc->sdtr_able = eep_config.sdtr_able;
15480 asc_dvc->ultra_able = eep_config.ultra_able;
15481 asc_dvc->tagqng_able = eep_config.tagqng_able;
15482 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15483 asc_dvc->max_host_qng = eep_config.max_host_qng;
15484 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15485 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15486 asc_dvc->start_motor = eep_config.start_motor;
15487 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15488 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15489 asc_dvc->no_scam = eep_config.scam_tolerant;
15490 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15491 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15492 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015494 /*
15495 * Set the host maximum queuing (max. 253, min. 16) and the per device
15496 * maximum queuing (max. 63, min. 4).
15497 */
15498 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15499 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15500 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15501 /* If the value is zero, assume it is uninitialized. */
15502 if (eep_config.max_host_qng == 0) {
15503 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15504 } else {
15505 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15506 }
15507 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015508
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015509 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15510 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15511 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15512 /* If the value is zero, assume it is uninitialized. */
15513 if (eep_config.max_dvc_qng == 0) {
15514 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15515 } else {
15516 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15517 }
15518 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015519
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015520 /*
15521 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15522 * set 'max_dvc_qng' to 'max_host_qng'.
15523 */
15524 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15525 eep_config.max_dvc_qng = eep_config.max_host_qng;
15526 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015527
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015528 /*
15529 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15530 * values based on possibly adjusted EEPROM values.
15531 */
15532 asc_dvc->max_host_qng = eep_config.max_host_qng;
15533 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015534
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015535 /*
15536 * If the EEPROM 'termination' field is set to automatic (0), then set
15537 * the ADV_DVC_CFG 'termination' field to automatic also.
15538 *
15539 * If the termination is specified with a non-zero 'termination'
15540 * value check that a legal value is set and set the ADV_DVC_CFG
15541 * 'termination' field appropriately.
15542 */
15543 if (eep_config.termination == 0) {
15544 asc_dvc->cfg->termination = 0; /* auto termination */
15545 } else {
15546 /* Enable manual control with low off / high off. */
15547 if (eep_config.termination == 1) {
15548 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015549
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015550 /* Enable manual control with low off / high on. */
15551 } else if (eep_config.termination == 2) {
15552 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015553
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015554 /* Enable manual control with low on / high on. */
15555 } else if (eep_config.termination == 3) {
15556 asc_dvc->cfg->termination =
15557 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
15558 } else {
15559 /*
15560 * The EEPROM 'termination' field contains a bad value. Use
15561 * automatic termination instead.
15562 */
15563 asc_dvc->cfg->termination = 0;
15564 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15565 }
15566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015567
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015568 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015569}
15570
15571/*
15572 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15573 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15574 * all of this is done.
15575 *
15576 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15577 *
15578 * For a non-fatal error return a warning code. If there are no warnings
15579 * then 0 is returned.
15580 *
15581 * Note: Chip is stopped on entry.
15582 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015583static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015584{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015585 AdvPortAddr iop_base;
15586 ushort warn_code;
15587 ADVEEP_38C0800_CONFIG eep_config;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015588 uchar tid, termination;
15589 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015590
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015591 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015592
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015593 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015594
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015595 /*
15596 * Read the board's EEPROM configuration.
15597 *
15598 * Set default values if a bad checksum is found.
15599 */
15600 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
15601 eep_config.check_sum) {
15602 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015603
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015604 /*
15605 * Set EEPROM default values.
15606 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040015607 memcpy(&eep_config, &Default_38C0800_EEPROM_Config,
15608 sizeof(ADVEEP_38C0800_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015609
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015610 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040015611 * Assume the 6 byte board serial number that was read from
15612 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015613 */
15614 eep_config.serial_number_word3 =
15615 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015616
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015617 eep_config.serial_number_word2 =
15618 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015619
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015620 eep_config.serial_number_word1 =
15621 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015622
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015623 AdvSet38C0800EEPConfig(iop_base, &eep_config);
15624 }
15625 /*
15626 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
15627 * EEPROM configuration that was read.
15628 *
15629 * This is the mapping of EEPROM fields to Adv Library fields.
15630 */
15631 asc_dvc->wdtr_able = eep_config.wdtr_able;
15632 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15633 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15634 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15635 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15636 asc_dvc->tagqng_able = eep_config.tagqng_able;
15637 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15638 asc_dvc->max_host_qng = eep_config.max_host_qng;
15639 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15640 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15641 asc_dvc->start_motor = eep_config.start_motor;
15642 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15643 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15644 asc_dvc->no_scam = eep_config.scam_tolerant;
15645 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15646 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15647 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015648
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015649 /*
15650 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15651 * are set, then set an 'sdtr_able' bit for it.
15652 */
15653 asc_dvc->sdtr_able = 0;
15654 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15655 if (tid == 0) {
15656 sdtr_speed = asc_dvc->sdtr_speed1;
15657 } else if (tid == 4) {
15658 sdtr_speed = asc_dvc->sdtr_speed2;
15659 } else if (tid == 8) {
15660 sdtr_speed = asc_dvc->sdtr_speed3;
15661 } else if (tid == 12) {
15662 sdtr_speed = asc_dvc->sdtr_speed4;
15663 }
15664 if (sdtr_speed & ADV_MAX_TID) {
15665 asc_dvc->sdtr_able |= (1 << tid);
15666 }
15667 sdtr_speed >>= 4;
15668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015669
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015670 /*
15671 * Set the host maximum queuing (max. 253, min. 16) and the per device
15672 * maximum queuing (max. 63, min. 4).
15673 */
15674 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15675 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15676 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15677 /* If the value is zero, assume it is uninitialized. */
15678 if (eep_config.max_host_qng == 0) {
15679 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15680 } else {
15681 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15682 }
15683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015684
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015685 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15686 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15687 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15688 /* If the value is zero, assume it is uninitialized. */
15689 if (eep_config.max_dvc_qng == 0) {
15690 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15691 } else {
15692 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15693 }
15694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015695
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015696 /*
15697 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15698 * set 'max_dvc_qng' to 'max_host_qng'.
15699 */
15700 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15701 eep_config.max_dvc_qng = eep_config.max_host_qng;
15702 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015703
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015704 /*
15705 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15706 * values based on possibly adjusted EEPROM values.
15707 */
15708 asc_dvc->max_host_qng = eep_config.max_host_qng;
15709 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015710
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015711 /*
15712 * If the EEPROM 'termination' field is set to automatic (0), then set
15713 * the ADV_DVC_CFG 'termination' field to automatic also.
15714 *
15715 * If the termination is specified with a non-zero 'termination'
15716 * value check that a legal value is set and set the ADV_DVC_CFG
15717 * 'termination' field appropriately.
15718 */
15719 if (eep_config.termination_se == 0) {
15720 termination = 0; /* auto termination for SE */
15721 } else {
15722 /* Enable manual control with low off / high off. */
15723 if (eep_config.termination_se == 1) {
15724 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015725
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015726 /* Enable manual control with low off / high on. */
15727 } else if (eep_config.termination_se == 2) {
15728 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015729
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015730 /* Enable manual control with low on / high on. */
15731 } else if (eep_config.termination_se == 3) {
15732 termination = TERM_SE;
15733 } else {
15734 /*
15735 * The EEPROM 'termination_se' field contains a bad value.
15736 * Use automatic termination instead.
15737 */
15738 termination = 0;
15739 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15740 }
15741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015742
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015743 if (eep_config.termination_lvd == 0) {
15744 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
15745 } else {
15746 /* Enable manual control with low off / high off. */
15747 if (eep_config.termination_lvd == 1) {
15748 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015749
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015750 /* Enable manual control with low off / high on. */
15751 } else if (eep_config.termination_lvd == 2) {
15752 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015753
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015754 /* Enable manual control with low on / high on. */
15755 } else if (eep_config.termination_lvd == 3) {
15756 asc_dvc->cfg->termination = termination | TERM_LVD;
15757 } else {
15758 /*
15759 * The EEPROM 'termination_lvd' field contains a bad value.
15760 * Use automatic termination instead.
15761 */
15762 asc_dvc->cfg->termination = termination;
15763 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15764 }
15765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015766
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015767 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015768}
15769
15770/*
15771 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
15772 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
15773 * all of this is done.
15774 *
15775 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15776 *
15777 * For a non-fatal error return a warning code. If there are no warnings
15778 * then 0 is returned.
15779 *
15780 * Note: Chip is stopped on entry.
15781 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015782static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015783{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015784 AdvPortAddr iop_base;
15785 ushort warn_code;
15786 ADVEEP_38C1600_CONFIG eep_config;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015787 uchar tid, termination;
15788 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015789
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015790 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015791
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015792 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015793
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015794 /*
15795 * Read the board's EEPROM configuration.
15796 *
15797 * Set default values if a bad checksum is found.
15798 */
15799 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
15800 eep_config.check_sum) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060015801 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015802 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015803
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015804 /*
15805 * Set EEPROM default values.
15806 */
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040015807 memcpy(&eep_config, &Default_38C1600_EEPROM_Config,
15808 sizeof(ADVEEP_38C1600_CONFIG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015809
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040015810 if (PCI_FUNC(pdev->devfn) != 0) {
15811 u8 ints;
15812 /*
15813 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60
15814 * and old Mac system booting problem. The Expansion
15815 * ROM must be disabled in Function 1 for these systems
15816 */
15817 eep_config.cfg_lsw &= ~ADV_EEPROM_BIOS_ENABLE;
15818 /*
15819 * Clear the INTAB (bit 11) if the GPIO 0 input
15820 * indicates the Function 1 interrupt line is wired
15821 * to INTB.
15822 *
15823 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
15824 * 1 - Function 1 interrupt line wired to INT A.
15825 * 0 - Function 1 interrupt line wired to INT B.
15826 *
15827 * Note: Function 0 is always wired to INTA.
15828 * Put all 5 GPIO bits in input mode and then read
15829 * their input values.
15830 */
15831 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
15832 ints = AdvReadByteRegister(iop_base, IOPB_GPIO_DATA);
15833 if ((ints & 0x01) == 0)
15834 eep_config.cfg_lsw &= ~ADV_EEPROM_INTAB;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015835 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015837 /*
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040015838 * Assume the 6 byte board serial number that was read from
15839 * EEPROM is correct even if the EEPROM checksum failed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015840 */
15841 eep_config.serial_number_word3 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040015842 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015843 eep_config.serial_number_word2 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040015844 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015845 eep_config.serial_number_word1 =
Matthew Wilcoxd68f4322007-07-26 11:58:12 -040015846 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015847
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015848 AdvSet38C1600EEPConfig(iop_base, &eep_config);
15849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015850
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015851 /*
15852 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15853 * EEPROM configuration that was read.
15854 *
15855 * This is the mapping of EEPROM fields to Adv Library fields.
15856 */
15857 asc_dvc->wdtr_able = eep_config.wdtr_able;
15858 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15859 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15860 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15861 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15862 asc_dvc->ppr_able = 0;
15863 asc_dvc->tagqng_able = eep_config.tagqng_able;
15864 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15865 asc_dvc->max_host_qng = eep_config.max_host_qng;
15866 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15867 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
15868 asc_dvc->start_motor = eep_config.start_motor;
15869 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15870 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15871 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015872
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015873 /*
15874 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15875 * are set, then set an 'sdtr_able' bit for it.
15876 */
15877 asc_dvc->sdtr_able = 0;
15878 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15879 if (tid == 0) {
15880 sdtr_speed = asc_dvc->sdtr_speed1;
15881 } else if (tid == 4) {
15882 sdtr_speed = asc_dvc->sdtr_speed2;
15883 } else if (tid == 8) {
15884 sdtr_speed = asc_dvc->sdtr_speed3;
15885 } else if (tid == 12) {
15886 sdtr_speed = asc_dvc->sdtr_speed4;
15887 }
15888 if (sdtr_speed & ASC_MAX_TID) {
15889 asc_dvc->sdtr_able |= (1 << tid);
15890 }
15891 sdtr_speed >>= 4;
15892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015893
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015894 /*
15895 * Set the host maximum queuing (max. 253, min. 16) and the per device
15896 * maximum queuing (max. 63, min. 4).
15897 */
15898 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15899 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15900 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15901 /* If the value is zero, assume it is uninitialized. */
15902 if (eep_config.max_host_qng == 0) {
15903 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15904 } else {
15905 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15906 }
15907 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015908
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015909 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15910 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15911 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15912 /* If the value is zero, assume it is uninitialized. */
15913 if (eep_config.max_dvc_qng == 0) {
15914 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15915 } else {
15916 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15917 }
15918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015919
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015920 /*
15921 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15922 * set 'max_dvc_qng' to 'max_host_qng'.
15923 */
15924 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15925 eep_config.max_dvc_qng = eep_config.max_host_qng;
15926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015927
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015928 /*
15929 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
15930 * values based on possibly adjusted EEPROM values.
15931 */
15932 asc_dvc->max_host_qng = eep_config.max_host_qng;
15933 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015934
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015935 /*
15936 * If the EEPROM 'termination' field is set to automatic (0), then set
15937 * the ASC_DVC_CFG 'termination' field to automatic also.
15938 *
15939 * If the termination is specified with a non-zero 'termination'
15940 * value check that a legal value is set and set the ASC_DVC_CFG
15941 * 'termination' field appropriately.
15942 */
15943 if (eep_config.termination_se == 0) {
15944 termination = 0; /* auto termination for SE */
15945 } else {
15946 /* Enable manual control with low off / high off. */
15947 if (eep_config.termination_se == 1) {
15948 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015949
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015950 /* Enable manual control with low off / high on. */
15951 } else if (eep_config.termination_se == 2) {
15952 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015953
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015954 /* Enable manual control with low on / high on. */
15955 } else if (eep_config.termination_se == 3) {
15956 termination = TERM_SE;
15957 } else {
15958 /*
15959 * The EEPROM 'termination_se' field contains a bad value.
15960 * Use automatic termination instead.
15961 */
15962 termination = 0;
15963 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15964 }
15965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015966
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015967 if (eep_config.termination_lvd == 0) {
15968 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
15969 } else {
15970 /* Enable manual control with low off / high off. */
15971 if (eep_config.termination_lvd == 1) {
15972 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015973
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015974 /* Enable manual control with low off / high on. */
15975 } else if (eep_config.termination_lvd == 2) {
15976 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015977
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015978 /* Enable manual control with low on / high on. */
15979 } else if (eep_config.termination_lvd == 3) {
15980 asc_dvc->cfg->termination = termination | TERM_LVD;
15981 } else {
15982 /*
15983 * The EEPROM 'termination_lvd' field contains a bad value.
15984 * Use automatic termination instead.
15985 */
15986 asc_dvc->cfg->termination = termination;
15987 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15988 }
15989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015990
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015991 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015992}
15993
15994/*
15995 * Read EEPROM configuration into the specified buffer.
15996 *
15997 * Return a checksum based on the EEPROM configuration read.
15998 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015999static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016000AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16001{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016002 ushort wval, chksum;
16003 ushort *wbuf;
16004 int eep_addr;
16005 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016006
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016007 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16008 wbuf = (ushort *)cfg_buf;
16009 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016011 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16012 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16013 wval = AdvReadEEPWord(iop_base, eep_addr);
16014 chksum += wval; /* Checksum is calculated from word values. */
16015 if (*charfields++) {
16016 *wbuf = le16_to_cpu(wval);
16017 } else {
16018 *wbuf = wval;
16019 }
16020 }
16021 /* Read checksum word. */
16022 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16023 wbuf++;
16024 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016025
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016026 /* Read rest of EEPROM not covered by the checksum. */
16027 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16028 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16029 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16030 if (*charfields++) {
16031 *wbuf = le16_to_cpu(*wbuf);
16032 }
16033 }
16034 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016035}
16036
16037/*
16038 * Read EEPROM configuration into the specified buffer.
16039 *
16040 * Return a checksum based on the EEPROM configuration read.
16041 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016042static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016043AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016044{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016045 ushort wval, chksum;
16046 ushort *wbuf;
16047 int eep_addr;
16048 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016049
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016050 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16051 wbuf = (ushort *)cfg_buf;
16052 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016053
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016054 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16055 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16056 wval = AdvReadEEPWord(iop_base, eep_addr);
16057 chksum += wval; /* Checksum is calculated from word values. */
16058 if (*charfields++) {
16059 *wbuf = le16_to_cpu(wval);
16060 } else {
16061 *wbuf = wval;
16062 }
16063 }
16064 /* Read checksum word. */
16065 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16066 wbuf++;
16067 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016068
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016069 /* Read rest of EEPROM not covered by the checksum. */
16070 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16071 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16072 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16073 if (*charfields++) {
16074 *wbuf = le16_to_cpu(*wbuf);
16075 }
16076 }
16077 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016078}
16079
16080/*
16081 * Read EEPROM configuration into the specified buffer.
16082 *
16083 * Return a checksum based on the EEPROM configuration read.
16084 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016085static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016086AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016087{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016088 ushort wval, chksum;
16089 ushort *wbuf;
16090 int eep_addr;
16091 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016092
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016093 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16094 wbuf = (ushort *)cfg_buf;
16095 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016096
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016097 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16098 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16099 wval = AdvReadEEPWord(iop_base, eep_addr);
16100 chksum += wval; /* Checksum is calculated from word values. */
16101 if (*charfields++) {
16102 *wbuf = le16_to_cpu(wval);
16103 } else {
16104 *wbuf = wval;
16105 }
16106 }
16107 /* Read checksum word. */
16108 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16109 wbuf++;
16110 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016111
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016112 /* Read rest of EEPROM not covered by the checksum. */
16113 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16114 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16115 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16116 if (*charfields++) {
16117 *wbuf = le16_to_cpu(*wbuf);
16118 }
16119 }
16120 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016121}
16122
16123/*
16124 * Read the EEPROM from specified location
16125 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016126static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016127{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016128 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16129 ASC_EEP_CMD_READ | eep_word_addr);
16130 AdvWaitEEPCmd(iop_base);
16131 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016132}
16133
16134/*
16135 * Wait for EEPROM command to complete
16136 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016137static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016138{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016139 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016140
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016141 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16142 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16143 ASC_EEP_CMD_DONE) {
16144 break;
16145 }
16146 DvcSleepMilliSecond(1);
16147 }
16148 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16149 0) {
16150 ASC_ASSERT(0);
16151 }
16152 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016153}
16154
16155/*
16156 * Write the EEPROM from 'cfg_buf'.
16157 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016158void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016159AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16160{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016161 ushort *wbuf;
16162 ushort addr, chksum;
16163 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016164
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016165 wbuf = (ushort *)cfg_buf;
16166 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16167 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016168
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016169 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16170 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016171
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016172 /*
16173 * Write EEPROM from word 0 to word 20.
16174 */
16175 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16176 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16177 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016178
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016179 if (*charfields++) {
16180 word = cpu_to_le16(*wbuf);
16181 } else {
16182 word = *wbuf;
16183 }
16184 chksum += *wbuf; /* Checksum is calculated from word values. */
16185 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16186 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16187 ASC_EEP_CMD_WRITE | addr);
16188 AdvWaitEEPCmd(iop_base);
16189 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016191
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016192 /*
16193 * Write EEPROM checksum at word 21.
16194 */
16195 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16196 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16197 AdvWaitEEPCmd(iop_base);
16198 wbuf++;
16199 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016200
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016201 /*
16202 * Write EEPROM OEM name at words 22 to 29.
16203 */
16204 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16205 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16206 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016207
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016208 if (*charfields++) {
16209 word = cpu_to_le16(*wbuf);
16210 } else {
16211 word = *wbuf;
16212 }
16213 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16214 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16215 ASC_EEP_CMD_WRITE | addr);
16216 AdvWaitEEPCmd(iop_base);
16217 }
16218 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16219 AdvWaitEEPCmd(iop_base);
16220 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016221}
16222
16223/*
16224 * Write the EEPROM from 'cfg_buf'.
16225 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016226void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016227AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016228{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016229 ushort *wbuf;
16230 ushort *charfields;
16231 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016232
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016233 wbuf = (ushort *)cfg_buf;
16234 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16235 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016236
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016237 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16238 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016239
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016240 /*
16241 * Write EEPROM from word 0 to word 20.
16242 */
16243 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16244 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16245 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016246
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016247 if (*charfields++) {
16248 word = cpu_to_le16(*wbuf);
16249 } else {
16250 word = *wbuf;
16251 }
16252 chksum += *wbuf; /* Checksum is calculated from word values. */
16253 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16254 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16255 ASC_EEP_CMD_WRITE | addr);
16256 AdvWaitEEPCmd(iop_base);
16257 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016259
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016260 /*
16261 * Write EEPROM checksum at word 21.
16262 */
16263 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16264 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16265 AdvWaitEEPCmd(iop_base);
16266 wbuf++;
16267 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016268
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016269 /*
16270 * Write EEPROM OEM name at words 22 to 29.
16271 */
16272 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16273 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16274 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016275
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016276 if (*charfields++) {
16277 word = cpu_to_le16(*wbuf);
16278 } else {
16279 word = *wbuf;
16280 }
16281 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16282 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16283 ASC_EEP_CMD_WRITE | addr);
16284 AdvWaitEEPCmd(iop_base);
16285 }
16286 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16287 AdvWaitEEPCmd(iop_base);
16288 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016289}
16290
16291/*
16292 * Write the EEPROM from 'cfg_buf'.
16293 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016294void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016295AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016296{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016297 ushort *wbuf;
16298 ushort *charfields;
16299 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016300
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016301 wbuf = (ushort *)cfg_buf;
16302 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16303 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016304
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016305 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16306 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016307
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016308 /*
16309 * Write EEPROM from word 0 to word 20.
16310 */
16311 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16312 addr < ADV_EEP_DVC_CFG_END; 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 chksum += *wbuf; /* Checksum is calculated from word values. */
16321 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16322 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16323 ASC_EEP_CMD_WRITE | addr);
16324 AdvWaitEEPCmd(iop_base);
16325 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016327
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016328 /*
16329 * Write EEPROM checksum at word 21.
16330 */
16331 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16332 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16333 AdvWaitEEPCmd(iop_base);
16334 wbuf++;
16335 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016336
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016337 /*
16338 * Write EEPROM OEM name at words 22 to 29.
16339 */
16340 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16341 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16342 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016343
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016344 if (*charfields++) {
16345 word = cpu_to_le16(*wbuf);
16346 } else {
16347 word = *wbuf;
16348 }
16349 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16350 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16351 ASC_EEP_CMD_WRITE | addr);
16352 AdvWaitEEPCmd(iop_base);
16353 }
16354 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16355 AdvWaitEEPCmd(iop_base);
16356 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016357}
16358
16359/* a_advlib.c */
16360/*
16361 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
16362 *
16363 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
16364 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
16365 * RISC to notify it a new command is ready to be executed.
16366 *
16367 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
16368 * set to SCSI_MAX_RETRY.
16369 *
16370 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
16371 * for DMA addresses or math operations are byte swapped to little-endian
16372 * order.
16373 *
16374 * Return:
16375 * ADV_SUCCESS(1) - The request was successfully queued.
16376 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
16377 * request completes.
16378 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
16379 * host IC error.
16380 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016381static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016382{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016383 ulong last_int_level;
16384 AdvPortAddr iop_base;
16385 ADV_DCNT req_size;
16386 ADV_PADDR req_paddr;
16387 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016388
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016389 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016390
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016391 /*
16392 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
16393 */
16394 if (scsiq->target_id > ADV_MAX_TID) {
16395 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
16396 scsiq->done_status = QD_WITH_ERROR;
16397 return ADV_ERROR;
16398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016399
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016400 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016401
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016402 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016403
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016404 /*
16405 * Allocate a carrier ensuring at least one carrier always
16406 * remains on the freelist and initialize fields.
16407 */
16408 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
16409 DvcLeaveCritical(last_int_level);
16410 return ADV_BUSY;
16411 }
16412 asc_dvc->carr_freelist = (ADV_CARR_T *)
16413 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
16414 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016415
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016416 /*
16417 * Set the carrier to be a stopper by setting 'next_vpa'
16418 * to the stopper value. The current stopper will be changed
16419 * below to point to the new stopper.
16420 */
16421 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016422
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016423 /*
16424 * Clear the ADV_SCSI_REQ_Q done flag.
16425 */
16426 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016427
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016428 req_size = sizeof(ADV_SCSI_REQ_Q);
16429 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
16430 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016431
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016432 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
16433 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016434
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016435 /* Wait for assertion before making little-endian */
16436 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016437
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016438 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
16439 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
16440 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016441
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016442 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
16443 /*
16444 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
16445 * order during initialization.
16446 */
16447 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016448
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016449 /*
16450 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
16451 * the microcode. The newly allocated stopper will become the new
16452 * stopper.
16453 */
16454 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016455
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016456 /*
16457 * Set the 'next_vpa' pointer for the old stopper to be the
16458 * physical address of the new stopper. The RISC can only
16459 * follow physical addresses.
16460 */
16461 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016462
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016463 /*
16464 * Set the host adapter stopper pointer to point to the new carrier.
16465 */
16466 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016467
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016468 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16469 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16470 /*
16471 * Tickle the RISC to tell it to read its Command Queue Head pointer.
16472 */
16473 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
16474 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16475 /*
16476 * Clear the tickle value. In the ASC-3550 the RISC flag
16477 * command 'clr_tickle_a' does not work unless the host
16478 * value is cleared.
16479 */
16480 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16481 ADV_TICKLE_NOP);
16482 }
16483 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16484 /*
16485 * Notify the RISC a carrier is ready by writing the physical
16486 * address of the new carrier stopper to the COMMA register.
16487 */
16488 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
16489 le32_to_cpu(new_carrp->carr_pa));
16490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016491
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016492 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016494 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016495}
16496
16497/*
16498 * Reset SCSI Bus and purge all outstanding requests.
16499 *
16500 * Return Value:
16501 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
16502 * ADV_FALSE(0) - Microcode command failed.
16503 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
16504 * may be hung which requires driver recovery.
16505 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016506static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016507{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016508 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016509
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016510 /*
16511 * Send the SCSI Bus Reset idle start idle command which asserts
16512 * the SCSI Bus Reset signal.
16513 */
16514 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
16515 if (status != ADV_TRUE) {
16516 return status;
16517 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016518
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016519 /*
16520 * Delay for the specified SCSI Bus Reset hold time.
16521 *
16522 * The hold time delay is done on the host because the RISC has no
16523 * microsecond accurate timer.
16524 */
16525 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016526
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016527 /*
16528 * Send the SCSI Bus Reset end idle command which de-asserts
16529 * the SCSI Bus Reset signal and purges any pending requests.
16530 */
16531 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
16532 if (status != ADV_TRUE) {
16533 return status;
16534 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016535
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016536 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016537
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016538 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016539}
16540
16541/*
16542 * Reset chip and SCSI Bus.
16543 *
16544 * Return Value:
16545 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
16546 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
16547 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016548static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016549{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016550 int status;
16551 ushort wdtr_able, sdtr_able, tagqng_able;
16552 ushort ppr_able = 0;
16553 uchar tid, max_cmd[ADV_MAX_TID + 1];
16554 AdvPortAddr iop_base;
16555 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016556
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016557 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016558
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016559 /*
16560 * Save current per TID negotiated values.
16561 */
16562 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16563 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16564 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16565 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16566 }
16567 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16568 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16569 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16570 max_cmd[tid]);
16571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016572
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016573 /*
16574 * Force the AdvInitAsc3550/38C0800Driver() function to
16575 * perform a SCSI Bus Reset by clearing the BIOS signature word.
16576 * The initialization functions assumes a SCSI Bus Reset is not
16577 * needed if the BIOS signature word is present.
16578 */
16579 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
16580 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016581
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016582 /*
16583 * Stop chip and reset it.
16584 */
16585 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
16586 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
16587 DvcSleepMilliSecond(100);
16588 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
16589 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016590
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016591 /*
16592 * Reset Adv Library error code, if any, and try
16593 * re-initializing the chip.
16594 */
16595 asc_dvc->err_code = 0;
16596 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16597 status = AdvInitAsc38C1600Driver(asc_dvc);
16598 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16599 status = AdvInitAsc38C0800Driver(asc_dvc);
16600 } else {
16601 status = AdvInitAsc3550Driver(asc_dvc);
16602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016603
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016604 /* Translate initialization return value to status value. */
16605 if (status == 0) {
16606 status = ADV_TRUE;
16607 } else {
16608 status = ADV_FALSE;
16609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016610
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016611 /*
16612 * Restore the BIOS signature word.
16613 */
16614 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016615
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016616 /*
16617 * Restore per TID negotiated values.
16618 */
16619 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16620 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16621 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16622 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16623 }
16624 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16625 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16626 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16627 max_cmd[tid]);
16628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016630 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016631}
16632
16633/*
16634 * Adv Library Interrupt Service Routine
16635 *
16636 * This function is called by a driver's interrupt service routine.
16637 * The function disables and re-enables interrupts.
16638 *
16639 * When a microcode idle command is completed, the ADV_DVC_VAR
16640 * 'idle_cmd_done' field is set to ADV_TRUE.
16641 *
16642 * Note: AdvISR() can be called when interrupts are disabled or even
16643 * when there is no hardware interrupt condition present. It will
16644 * always check for completed idle commands and microcode requests.
16645 * This is an important feature that shouldn't be changed because it
16646 * allows commands to be completed from polling mode loops.
16647 *
16648 * Return:
16649 * ADV_TRUE(1) - interrupt was pending
16650 * ADV_FALSE(0) - no interrupt was pending
16651 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016652static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016653{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016654 AdvPortAddr iop_base;
16655 uchar int_stat;
16656 ushort target_bit;
16657 ADV_CARR_T *free_carrp;
16658 ADV_VADDR irq_next_vpa;
16659 int flags;
16660 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016661
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016662 flags = DvcEnterCritical();
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 /* Reading the register clears the interrupt. */
16667 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016668
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016669 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
16670 ADV_INTR_STATUS_INTRC)) == 0) {
16671 DvcLeaveCritical(flags);
16672 return ADV_FALSE;
16673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016674
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016675 /*
16676 * Notify the driver of an asynchronous microcode condition by
Matthew Wilcox895d6b42007-07-26 11:57:06 -040016677 * calling the adv_async_callback function. The function
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016678 * is passed the microcode ASC_MC_INTRB_CODE byte value.
16679 */
16680 if (int_stat & ADV_INTR_STATUS_INTRB) {
16681 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016682
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016683 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016684
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016685 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16686 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16687 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
16688 asc_dvc->carr_pending_cnt != 0) {
16689 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16690 ADV_TICKLE_A);
16691 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16692 AdvWriteByteRegister(iop_base,
16693 IOPB_TICKLE,
16694 ADV_TICKLE_NOP);
16695 }
16696 }
16697 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016698
Matthew Wilcox895d6b42007-07-26 11:57:06 -040016699 adv_async_callback(asc_dvc, intrb_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016701
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016702 /*
16703 * Check if the IRQ stopper carrier contains a completed request.
16704 */
16705 while (((irq_next_vpa =
16706 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
16707 /*
16708 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
16709 * The RISC will have set 'areq_vpa' to a virtual address.
16710 *
16711 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
16712 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
16713 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
16714 * in AdvExeScsiQueue().
16715 */
16716 scsiq = (ADV_SCSI_REQ_Q *)
16717 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016718
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016719 /*
16720 * Request finished with good status and the queue was not
16721 * DMAed to host memory by the firmware. Set all status fields
16722 * to indicate good status.
16723 */
16724 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
16725 scsiq->done_status = QD_NO_ERROR;
16726 scsiq->host_status = scsiq->scsi_status = 0;
16727 scsiq->data_cnt = 0L;
16728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016729
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016730 /*
16731 * Advance the stopper pointer to the next carrier
16732 * ignoring the lower four bits. Free the previous
16733 * stopper carrier.
16734 */
16735 free_carrp = asc_dvc->irq_sp;
16736 asc_dvc->irq_sp = (ADV_CARR_T *)
16737 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016738
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016739 free_carrp->next_vpa =
16740 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
16741 asc_dvc->carr_freelist = free_carrp;
16742 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016743
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016744 ASC_ASSERT(scsiq != NULL);
16745 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016746
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016747 /*
16748 * Clear request microcode control flag.
16749 */
16750 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016751
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016752 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016753 * Notify the driver of the completed request by passing
16754 * the ADV_SCSI_REQ_Q pointer to its callback function.
16755 */
16756 scsiq->a_flag |= ADV_SCSIQ_DONE;
Matthew Wilcox895d6b42007-07-26 11:57:06 -040016757 adv_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016758 /*
16759 * Note: After the driver callback function is called, 'scsiq'
16760 * can no longer be referenced.
16761 *
16762 * Fall through and continue processing other completed
16763 * requests...
16764 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016765
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016766 /*
16767 * Disable interrupts again in case the driver inadvertently
16768 * enabled interrupts in its callback function.
16769 *
16770 * The DvcEnterCritical() return value is ignored, because
16771 * the 'flags' saved when AdvISR() was first entered will be
16772 * used to restore the interrupt flag on exit.
16773 */
16774 (void)DvcEnterCritical();
16775 }
16776 DvcLeaveCritical(flags);
16777 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016778}
16779
16780/*
16781 * Send an idle command to the chip and wait for completion.
16782 *
16783 * Command completion is polled for once per microsecond.
16784 *
16785 * The function can be called from anywhere including an interrupt handler.
16786 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
16787 * functions to prevent reentrancy.
16788 *
16789 * Return Values:
16790 * ADV_TRUE - command completed successfully
16791 * ADV_FALSE - command failed
16792 * ADV_ERROR - command timed out
16793 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016794static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070016795AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016796 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016797{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016798 ulong last_int_level;
16799 int result;
16800 ADV_DCNT i, j;
16801 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016802
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016803 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016804
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016805 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016807 /*
16808 * Clear the idle command status which is set by the microcode
16809 * to a non-zero value to indicate when the command is completed.
16810 * The non-zero result is one of the IDLE_CMD_STATUS_* values
16811 * defined in a_advlib.h.
16812 */
16813 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016814
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016815 /*
16816 * Write the idle command value after the idle command parameter
16817 * has been written to avoid a race condition. If the order is not
16818 * followed, the microcode may process the idle command before the
16819 * parameters have been written to LRAM.
16820 */
16821 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
16822 cpu_to_le32(idle_cmd_parameter));
16823 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016824
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016825 /*
16826 * Tickle the RISC to tell it to process the idle command.
16827 */
16828 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
16829 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16830 /*
16831 * Clear the tickle value. In the ASC-3550 the RISC flag
16832 * command 'clr_tickle_b' does not work unless the host
16833 * value is cleared.
16834 */
16835 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
16836 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016837
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016838 /* Wait for up to 100 millisecond for the idle command to timeout. */
16839 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
16840 /* Poll once each microsecond for command completion. */
16841 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
16842 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
16843 result);
16844 if (result != 0) {
16845 DvcLeaveCritical(last_int_level);
16846 return result;
16847 }
16848 DvcDelayMicroSecond(asc_dvc, (ushort)1);
16849 }
16850 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016851
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016852 ASC_ASSERT(0); /* The idle command should never timeout. */
16853 DvcLeaveCritical(last_int_level);
16854 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016855}
16856
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060016857static int __devinit
16858advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
16859{
16860 int req_cnt = 0;
16861 adv_req_t *reqp = NULL;
16862 int sg_cnt = 0;
16863 adv_sgblk_t *sgp;
16864 int warn_code, err_code;
16865
16866 /*
16867 * Allocate buffer carrier structures. The total size
16868 * is about 4 KB, so allocate all at once.
16869 */
16870 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
16871 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
16872
16873 if (!boardp->carrp)
16874 goto kmalloc_failed;
16875
16876 /*
16877 * Allocate up to 'max_host_qng' request structures for the Wide
16878 * board. The total size is about 16 KB, so allocate all at once.
16879 * If the allocation fails decrement and try again.
16880 */
16881 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
16882 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
16883
16884 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
16885 "bytes %lu\n", reqp, req_cnt,
16886 (ulong)sizeof(adv_req_t) * req_cnt);
16887
16888 if (reqp)
16889 break;
16890 }
16891
16892 if (!reqp)
16893 goto kmalloc_failed;
16894
16895 boardp->orig_reqp = reqp;
16896
16897 /*
16898 * Allocate up to ADV_TOT_SG_BLOCK request structures for
16899 * the Wide board. Each structure is about 136 bytes.
16900 */
16901 boardp->adv_sgblkp = NULL;
16902 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
16903 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
16904
16905 if (!sgp)
16906 break;
16907
16908 sgp->next_sgblkp = boardp->adv_sgblkp;
16909 boardp->adv_sgblkp = sgp;
16910
16911 }
16912
16913 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
16914 sg_cnt, sizeof(adv_sgblk_t),
16915 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
16916
16917 if (!boardp->adv_sgblkp)
16918 goto kmalloc_failed;
16919
16920 adv_dvc_varp->carrier_buf = boardp->carrp;
16921
16922 /*
16923 * Point 'adv_reqp' to the request structures and
16924 * link them together.
16925 */
16926 req_cnt--;
16927 reqp[req_cnt].next_reqp = NULL;
16928 for (; req_cnt > 0; req_cnt--) {
16929 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
16930 }
16931 boardp->adv_reqp = &reqp[0];
16932
16933 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
16934 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
16935 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
16936 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
16937 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
16938 "\n");
16939 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
16940 } else {
16941 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
16942 "\n");
16943 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
16944 }
16945 err_code = adv_dvc_varp->err_code;
16946
16947 if (warn_code || err_code) {
16948 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
16949 " error 0x%x\n", boardp->id, warn_code, err_code);
16950 }
16951
16952 goto exit;
16953
16954 kmalloc_failed:
16955 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
16956 "failed\n", boardp->id);
16957 err_code = ADV_ERROR;
16958 exit:
16959 return err_code;
16960}
16961
16962static void advansys_wide_free_mem(asc_board_t *boardp)
16963{
16964 kfree(boardp->carrp);
16965 boardp->carrp = NULL;
16966 kfree(boardp->orig_reqp);
16967 boardp->orig_reqp = boardp->adv_reqp = NULL;
16968 while (boardp->adv_sgblkp) {
16969 adv_sgblk_t *sgp = boardp->adv_sgblkp;
16970 boardp->adv_sgblkp = sgp->next_sgblkp;
16971 kfree(sgp);
16972 }
16973}
16974
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016975static struct Scsi_Host *__devinit
16976advansys_board_found(int iop, struct device *dev, int bus_type)
16977{
16978 struct Scsi_Host *shost;
16979 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
16980 asc_board_t *boardp;
16981 ASC_DVC_VAR *asc_dvc_varp = NULL;
16982 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060016983 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016984 int warn_code, err_code;
16985 int ret;
16986
16987 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016988 * Register the adapter, get its configuration, and
16989 * initialize it.
16990 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060016991 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
16992 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016993 if (!shost)
16994 return NULL;
16995
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016996 /* Initialize private per board data */
16997 boardp = ASC_BOARDP(shost);
16998 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016999 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017000 spin_lock_init(&boardp->lock);
Matthew Wilcox394dbf32007-07-26 11:56:40 -040017001 boardp->dev = dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017002
17003 /*
17004 * Handle both narrow and wide boards.
17005 *
17006 * If a Wide board was detected, set the board structure
17007 * wide board flag. Set-up the board structure based on
17008 * the board type.
17009 */
17010#ifdef CONFIG_PCI
17011 if (bus_type == ASC_IS_PCI &&
17012 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17013 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17014 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17015 boardp->flags |= ASC_IS_WIDE_BOARD;
17016 }
17017#endif /* CONFIG_PCI */
17018
17019 if (ASC_NARROW_BOARD(boardp)) {
17020 ASC_DBG(1, "advansys_board_found: narrow board\n");
17021 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17022 asc_dvc_varp->bus_type = bus_type;
17023 asc_dvc_varp->drv_ptr = boardp;
17024 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17025 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17026 asc_dvc_varp->iop_base = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017027 } else {
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017028#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017029 ASC_DBG(1, "advansys_board_found: wide board\n");
17030 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17031 adv_dvc_varp->drv_ptr = boardp;
17032 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017033 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17034 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17035 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17036 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17037 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17038 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17039 } else {
17040 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17041 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17042 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017043
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017044 boardp->asc_n_io_port = pci_resource_len(pdev, 1);
17045 boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
17046 boardp->asc_n_io_port);
17047 if (!boardp->ioremap_addr) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017048 ASC_PRINT3
17049 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017050 boardp->id, pci_resource_start(pdev, 1),
17051 boardp->asc_n_io_port);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017052 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017053 }
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017054 adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr
Matthew Wilcox71f361152007-07-30 08:04:53 -060017055 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017056 adv_dvc_varp->iop_base);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017057
17058 /*
17059 * Even though it isn't used to access wide boards, other
17060 * than for the debug line below, save I/O Port address so
17061 * that it can be reported.
17062 */
17063 boardp->ioport = iop;
17064
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017065 ASC_DBG2(1, "advansys_board_found: iopb_chip_id_1 0x%x, "
17066 "iopw_chip_id_0 0x%x\n", (ushort)inp(iop + 1),
17067 (ushort)inpw(iop));
17068#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017069 }
17070
17071#ifdef CONFIG_PROC_FS
17072 /*
17073 * Allocate buffer for printing information from
17074 * /proc/scsi/advansys/[0...].
17075 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017076 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
17077 if (!boardp->prtbuf) {
17078 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
17079 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
17080 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017081 }
17082#endif /* CONFIG_PROC_FS */
17083
17084 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017085 /*
17086 * Set the board bus type and PCI IRQ before
17087 * calling AscInitGetConfig().
17088 */
17089 switch (asc_dvc_varp->bus_type) {
17090#ifdef CONFIG_ISA
17091 case ASC_IS_ISA:
17092 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017093 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017094 break;
17095 case ASC_IS_VL:
17096 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017097 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017098 break;
17099 case ASC_IS_EISA:
17100 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017101 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017102 break;
17103#endif /* CONFIG_ISA */
17104#ifdef CONFIG_PCI
17105 case ASC_IS_PCI:
17106 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017107 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017108 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017109 break;
17110#endif /* CONFIG_PCI */
17111 default:
17112 ASC_PRINT2
17113 ("advansys_board_found: board %d: unknown adapter type: %d\n",
17114 boardp->id, asc_dvc_varp->bus_type);
17115 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017116 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017117 break;
17118 }
17119 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017120 /*
17121 * For Wide boards set PCI information before calling
17122 * AdvInitGetConfig().
17123 */
17124#ifdef CONFIG_PCI
17125 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017126 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017127 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017128#endif /* CONFIG_PCI */
17129 }
17130
17131 /*
17132 * Read the board configuration.
17133 */
17134 if (ASC_NARROW_BOARD(boardp)) {
17135 /*
17136 * NOTE: AscInitGetConfig() may change the board's
17137 * bus_type value. The bus_type value should no
17138 * longer be used. If the bus_type field must be
17139 * referenced only use the bit-wise AND operator "&".
17140 */
17141 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
17142 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
17143 case 0: /* No error */
17144 break;
17145 case ASC_WARN_IO_PORT_ROTATE:
17146 ASC_PRINT1
17147 ("AscInitGetConfig: board %d: I/O port address modified\n",
17148 boardp->id);
17149 break;
17150 case ASC_WARN_AUTO_CONFIG:
17151 ASC_PRINT1
17152 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
17153 boardp->id);
17154 break;
17155 case ASC_WARN_EEPROM_CHKSUM:
17156 ASC_PRINT1
17157 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
17158 boardp->id);
17159 break;
17160 case ASC_WARN_IRQ_MODIFIED:
17161 ASC_PRINT1
17162 ("AscInitGetConfig: board %d: IRQ modified\n",
17163 boardp->id);
17164 break;
17165 case ASC_WARN_CMD_QNG_CONFLICT:
17166 ASC_PRINT1
17167 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
17168 boardp->id);
17169 break;
17170 default:
17171 ASC_PRINT2
17172 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
17173 boardp->id, ret);
17174 break;
17175 }
17176 if ((err_code = asc_dvc_varp->err_code) != 0) {
17177 ASC_PRINT3
17178 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17179 boardp->id,
17180 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
17181 }
17182 } else {
17183 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
Matthew Wilcox394dbf32007-07-26 11:56:40 -040017184
17185 ret = AdvInitGetConfig(pdev, adv_dvc_varp);
17186 if (ret != 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017187 ASC_PRINT2
17188 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
17189 boardp->id, ret);
17190 }
17191 if ((err_code = adv_dvc_varp->err_code) != 0) {
17192 ASC_PRINT2
17193 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
17194 boardp->id, adv_dvc_varp->err_code);
17195 }
17196 }
17197
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017198 if (err_code != 0)
17199 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017200
17201 /*
17202 * Save the EEPROM configuration so that it can be displayed
17203 * from /proc/scsi/advansys/[0...].
17204 */
17205 if (ASC_NARROW_BOARD(boardp)) {
17206
17207 ASCEEP_CONFIG *ep;
17208
17209 /*
17210 * Set the adapter's target id bit in the 'init_tidmask' field.
17211 */
17212 boardp->init_tidmask |=
17213 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
17214
17215 /*
17216 * Save EEPROM settings for the board.
17217 */
17218 ep = &boardp->eep_config.asc_eep;
17219
17220 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
17221 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
17222 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
17223 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
17224 ep->start_motor = asc_dvc_varp->start_motor;
17225 ep->cntl = asc_dvc_varp->dvc_cntl;
17226 ep->no_scam = asc_dvc_varp->no_scam;
17227 ep->max_total_qng = asc_dvc_varp->max_total_qng;
17228 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
17229 /* 'max_tag_qng' is set to the same value for every device. */
17230 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
17231 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
17232 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
17233 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
17234 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
17235 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
17236 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
17237
17238 /*
17239 * Modify board configuration.
17240 */
17241 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
Matthew Wilcox394dbf32007-07-26 11:56:40 -040017242 switch (ret = AscInitSetConfig(pdev, asc_dvc_varp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017243 case 0: /* No error. */
17244 break;
17245 case ASC_WARN_IO_PORT_ROTATE:
17246 ASC_PRINT1
17247 ("AscInitSetConfig: board %d: I/O port address modified\n",
17248 boardp->id);
17249 break;
17250 case ASC_WARN_AUTO_CONFIG:
17251 ASC_PRINT1
17252 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
17253 boardp->id);
17254 break;
17255 case ASC_WARN_EEPROM_CHKSUM:
17256 ASC_PRINT1
17257 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
17258 boardp->id);
17259 break;
17260 case ASC_WARN_IRQ_MODIFIED:
17261 ASC_PRINT1
17262 ("AscInitSetConfig: board %d: IRQ modified\n",
17263 boardp->id);
17264 break;
17265 case ASC_WARN_CMD_QNG_CONFLICT:
17266 ASC_PRINT1
17267 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
17268 boardp->id);
17269 break;
17270 default:
17271 ASC_PRINT2
17272 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
17273 boardp->id, ret);
17274 break;
17275 }
17276 if (asc_dvc_varp->err_code != 0) {
17277 ASC_PRINT3
17278 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17279 boardp->id,
17280 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017281 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017282 }
17283
17284 /*
17285 * Finish initializing the 'Scsi_Host' structure.
17286 */
17287 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
17288 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
17289 shost->irq = asc_dvc_varp->irq_no;
17290 }
17291 } else {
17292 ADVEEP_3550_CONFIG *ep_3550;
17293 ADVEEP_38C0800_CONFIG *ep_38C0800;
17294 ADVEEP_38C1600_CONFIG *ep_38C1600;
17295
17296 /*
17297 * Save Wide EEP Configuration Information.
17298 */
17299 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17300 ep_3550 = &boardp->eep_config.adv_3550_eep;
17301
17302 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
17303 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
17304 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17305 ep_3550->termination = adv_dvc_varp->cfg->termination;
17306 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
17307 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
17308 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
17309 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
17310 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
17311 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
17312 ep_3550->start_motor = adv_dvc_varp->start_motor;
17313 ep_3550->scsi_reset_delay =
17314 adv_dvc_varp->scsi_reset_wait;
17315 ep_3550->serial_number_word1 =
17316 adv_dvc_varp->cfg->serial1;
17317 ep_3550->serial_number_word2 =
17318 adv_dvc_varp->cfg->serial2;
17319 ep_3550->serial_number_word3 =
17320 adv_dvc_varp->cfg->serial3;
17321 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17322 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
17323
17324 ep_38C0800->adapter_scsi_id =
17325 adv_dvc_varp->chip_scsi_id;
17326 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
17327 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17328 ep_38C0800->termination_lvd =
17329 adv_dvc_varp->cfg->termination;
17330 ep_38C0800->disc_enable =
17331 adv_dvc_varp->cfg->disc_enable;
17332 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
17333 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
17334 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17335 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17336 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17337 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17338 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17339 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17340 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
17341 ep_38C0800->scsi_reset_delay =
17342 adv_dvc_varp->scsi_reset_wait;
17343 ep_38C0800->serial_number_word1 =
17344 adv_dvc_varp->cfg->serial1;
17345 ep_38C0800->serial_number_word2 =
17346 adv_dvc_varp->cfg->serial2;
17347 ep_38C0800->serial_number_word3 =
17348 adv_dvc_varp->cfg->serial3;
17349 } else {
17350 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
17351
17352 ep_38C1600->adapter_scsi_id =
17353 adv_dvc_varp->chip_scsi_id;
17354 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
17355 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17356 ep_38C1600->termination_lvd =
17357 adv_dvc_varp->cfg->termination;
17358 ep_38C1600->disc_enable =
17359 adv_dvc_varp->cfg->disc_enable;
17360 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
17361 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
17362 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17363 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17364 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17365 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17366 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17367 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17368 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
17369 ep_38C1600->scsi_reset_delay =
17370 adv_dvc_varp->scsi_reset_wait;
17371 ep_38C1600->serial_number_word1 =
17372 adv_dvc_varp->cfg->serial1;
17373 ep_38C1600->serial_number_word2 =
17374 adv_dvc_varp->cfg->serial2;
17375 ep_38C1600->serial_number_word3 =
17376 adv_dvc_varp->cfg->serial3;
17377 }
17378
17379 /*
17380 * Set the adapter's target id bit in the 'init_tidmask' field.
17381 */
17382 boardp->init_tidmask |=
17383 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017384 }
17385
17386 /*
17387 * Channels are numbered beginning with 0. For AdvanSys one host
17388 * structure supports one channel. Multi-channel boards have a
17389 * separate host structure for each channel.
17390 */
17391 shost->max_channel = 0;
17392 if (ASC_NARROW_BOARD(boardp)) {
17393 shost->max_id = ASC_MAX_TID + 1;
17394 shost->max_lun = ASC_MAX_LUN + 1;
17395
17396 shost->io_port = asc_dvc_varp->iop_base;
17397 boardp->asc_n_io_port = ASC_IOADR_GAP;
17398 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
17399
17400 /* Set maximum number of queues the adapter can handle. */
17401 shost->can_queue = asc_dvc_varp->max_total_qng;
17402 } else {
17403 shost->max_id = ADV_MAX_TID + 1;
17404 shost->max_lun = ADV_MAX_LUN + 1;
17405
17406 /*
17407 * Save the I/O Port address and length even though
17408 * I/O ports are not used to access Wide boards.
17409 * Instead the Wide boards are accessed with
17410 * PCI Memory Mapped I/O.
17411 */
17412 shost->io_port = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017413
17414 shost->this_id = adv_dvc_varp->chip_scsi_id;
17415
17416 /* Set maximum number of queues the adapter can handle. */
17417 shost->can_queue = adv_dvc_varp->max_host_qng;
17418 }
17419
17420 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017421 * Following v1.3.89, 'cmd_per_lun' is no longer needed
17422 * and should be set to zero.
17423 *
17424 * But because of a bug introduced in v1.3.89 if the driver is
17425 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
17426 * SCSI function 'allocate_device' will panic. To allow the driver
17427 * to work as a module in these kernels set 'cmd_per_lun' to 1.
17428 *
17429 * Note: This is wrong. cmd_per_lun should be set to the depth
17430 * you want on untagged devices always.
17431 #ifdef MODULE
17432 */
17433 shost->cmd_per_lun = 1;
17434/* #else
17435 shost->cmd_per_lun = 0;
17436#endif */
17437
17438 /*
17439 * Set the maximum number of scatter-gather elements the
17440 * adapter can handle.
17441 */
17442 if (ASC_NARROW_BOARD(boardp)) {
17443 /*
17444 * Allow two commands with 'sg_tablesize' scatter-gather
17445 * elements to be executed simultaneously. This value is
17446 * the theoretical hardware limit. It may be decreased
17447 * below.
17448 */
17449 shost->sg_tablesize =
17450 (((asc_dvc_varp->max_total_qng - 2) / 2) *
17451 ASC_SG_LIST_PER_Q) + 1;
17452 } else {
17453 shost->sg_tablesize = ADV_MAX_SG_LIST;
17454 }
17455
17456 /*
17457 * The value of 'sg_tablesize' can not exceed the SCSI
17458 * mid-level driver definition of SG_ALL. SG_ALL also
17459 * must not be exceeded, because it is used to define the
17460 * size of the scatter-gather table in 'struct asc_sg_head'.
17461 */
17462 if (shost->sg_tablesize > SG_ALL) {
17463 shost->sg_tablesize = SG_ALL;
17464 }
17465
17466 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
17467
17468 /* BIOS start address. */
17469 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017470 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
17471 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017472 } else {
17473 /*
17474 * Fill-in BIOS board variables. The Wide BIOS saves
17475 * information in LRAM that is used by the driver.
17476 */
17477 AdvReadWordLram(adv_dvc_varp->iop_base,
17478 BIOS_SIGNATURE, boardp->bios_signature);
17479 AdvReadWordLram(adv_dvc_varp->iop_base,
17480 BIOS_VERSION, boardp->bios_version);
17481 AdvReadWordLram(adv_dvc_varp->iop_base,
17482 BIOS_CODESEG, boardp->bios_codeseg);
17483 AdvReadWordLram(adv_dvc_varp->iop_base,
17484 BIOS_CODELEN, boardp->bios_codelen);
17485
17486 ASC_DBG2(1,
17487 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
17488 boardp->bios_signature, boardp->bios_version);
17489
17490 ASC_DBG2(1,
17491 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
17492 boardp->bios_codeseg, boardp->bios_codelen);
17493
17494 /*
17495 * If the BIOS saved a valid signature, then fill in
17496 * the BIOS code segment base address.
17497 */
17498 if (boardp->bios_signature == 0x55AA) {
17499 /*
17500 * Convert x86 realmode code segment to a linear
17501 * address by shifting left 4.
17502 */
17503 shost->base = ((ulong)boardp->bios_codeseg << 4);
17504 } else {
17505 shost->base = 0;
17506 }
17507 }
17508
17509 /*
17510 * Register Board Resources - I/O Port, DMA, IRQ
17511 */
17512
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017513 /* Register DMA Channel for Narrow boards. */
17514 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
17515#ifdef CONFIG_ISA
17516 if (ASC_NARROW_BOARD(boardp)) {
17517 /* Register DMA channel for ISA bus. */
17518 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
17519 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017520 ret = request_dma(shost->dma_channel, "advansys");
17521 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017522 ASC_PRINT3
17523 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
17524 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f361152007-07-30 08:04:53 -060017525 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017526 }
17527 AscEnableIsaDma(shost->dma_channel);
17528 }
17529 }
17530#endif /* CONFIG_ISA */
17531
17532 /* Register IRQ Number. */
17533 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017534
17535 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
17536 "advansys", shost);
17537
17538 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017539 if (ret == -EBUSY) {
17540 ASC_PRINT2
17541 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
17542 boardp->id, shost->irq);
17543 } else if (ret == -EINVAL) {
17544 ASC_PRINT2
17545 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
17546 boardp->id, shost->irq);
17547 } else {
17548 ASC_PRINT3
17549 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
17550 boardp->id, shost->irq, ret);
17551 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017552 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017553 }
17554
17555 /*
17556 * Initialize board RISC chip and enable interrupts.
17557 */
17558 if (ASC_NARROW_BOARD(boardp)) {
17559 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
17560 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
17561 err_code = asc_dvc_varp->err_code;
17562
17563 if (warn_code || err_code) {
17564 ASC_PRINT4
17565 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
17566 boardp->id,
17567 asc_dvc_varp->init_state, warn_code, err_code);
17568 }
17569 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017570 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017571 }
17572
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017573 if (err_code != 0)
17574 goto err_free_wide_mem;
17575
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017576 ASC_DBG_PRT_SCSI_HOST(2, shost);
17577
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017578 ret = scsi_add_host(shost, dev);
17579 if (ret)
17580 goto err_free_wide_mem;
17581
17582 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017583 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017584
17585 err_free_wide_mem:
17586 advansys_wide_free_mem(boardp);
17587 free_irq(shost->irq, shost);
17588 err_free_dma:
17589 if (shost->dma_channel != NO_ISA_DMA)
17590 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017591 err_free_proc:
17592 kfree(boardp->prtbuf);
17593 err_unmap:
17594 if (boardp->ioremap_addr)
17595 iounmap(boardp->ioremap_addr);
17596 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017597 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017598 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017599}
17600
17601/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017602 * advansys_release()
17603 *
17604 * Release resources allocated for a single AdvanSys adapter.
17605 */
17606static int advansys_release(struct Scsi_Host *shost)
17607{
17608 asc_board_t *boardp;
17609
17610 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017611 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017612 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017613 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017614 if (shost->dma_channel != NO_ISA_DMA) {
17615 ASC_DBG(1, "advansys_release: free_dma()\n");
17616 free_dma(shost->dma_channel);
17617 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017618 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017619 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017620 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017621 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017622 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017623 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017624 ASC_DBG(1, "advansys_release: end\n");
17625 return 0;
17626}
17627
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017628static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
17629 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
17630 0x0210, 0x0230, 0x0250, 0x0330
17631};
17632
17633static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
17634{
17635 PortAddr iop_base = _asc_def_iop_base[id];
17636 struct Scsi_Host *shost;
17637
17638 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060017639 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
17640 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017641 return -ENODEV;
17642 }
17643 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017644 if (!AscFindSignature(iop_base))
17645 goto nodev;
17646 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
17647 goto nodev;
17648
17649 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017650 if (!shost)
17651 goto nodev;
17652
17653 dev_set_drvdata(dev, shost);
17654 return 0;
17655
17656 nodev:
Matthew Wilcox71f361152007-07-30 08:04:53 -060017657 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017658 return -ENODEV;
17659}
17660
17661static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
17662{
Matthew Wilcox71f361152007-07-30 08:04:53 -060017663 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017664 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f361152007-07-30 08:04:53 -060017665 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017666 return 0;
17667}
17668
17669static struct isa_driver advansys_isa_driver = {
17670 .probe = advansys_isa_probe,
17671 .remove = __devexit_p(advansys_isa_remove),
17672 .driver = {
17673 .owner = THIS_MODULE,
17674 .name = "advansys",
17675 },
17676};
17677
17678static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
17679{
17680 PortAddr iop_base = _asc_def_iop_base[id];
17681 struct Scsi_Host *shost;
17682
17683 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060017684 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
17685 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017686 return -ENODEV;
17687 }
17688 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017689 if (!AscFindSignature(iop_base))
17690 goto nodev;
17691 /*
17692 * I don't think this condition can actually happen, but the old
17693 * driver did it, and the chances of finding a VLB setup in 2007
17694 * to do testing with is slight to none.
17695 */
17696 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
17697 goto nodev;
17698
17699 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017700 if (!shost)
17701 goto nodev;
17702
17703 dev_set_drvdata(dev, shost);
17704 return 0;
17705
17706 nodev:
Matthew Wilcox71f361152007-07-30 08:04:53 -060017707 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017708 return -ENODEV;
17709}
17710
17711static struct isa_driver advansys_vlb_driver = {
17712 .probe = advansys_vlb_probe,
17713 .remove = __devexit_p(advansys_isa_remove),
17714 .driver = {
17715 .owner = THIS_MODULE,
17716 .name = "advansys",
17717 },
17718};
17719
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017720static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
17721 { "ABP7401" },
17722 { "ABP7501" },
17723 { "" }
17724};
17725
17726MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
17727
17728/*
17729 * EISA is a little more tricky than PCI; each EISA device may have two
17730 * channels, and this driver is written to make each channel its own Scsi_Host
17731 */
17732struct eisa_scsi_data {
17733 struct Scsi_Host *host[2];
17734};
17735
17736static int __devinit advansys_eisa_probe(struct device *dev)
17737{
17738 int i, ioport;
17739 int err;
17740 struct eisa_device *edev = to_eisa_device(dev);
17741 struct eisa_scsi_data *data;
17742
17743 err = -ENOMEM;
17744 data = kzalloc(sizeof(*data), GFP_KERNEL);
17745 if (!data)
17746 goto fail;
17747 ioport = edev->base_addr + 0xc30;
17748
17749 err = -ENODEV;
17750 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060017751 if (!request_region(ioport, ASC_IOADR_GAP, "advansys")) {
17752 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
17753 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017754 continue;
Matthew Wilcox71f361152007-07-30 08:04:53 -060017755 }
17756 if (!AscFindSignature(ioport)) {
17757 release_region(ioport, ASC_IOADR_GAP);
17758 continue;
17759 }
17760
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017761 /*
17762 * I don't know why we need to do this for EISA chips, but
17763 * not for any others. It looks to be equivalent to
17764 * AscGetChipCfgMsw, but I may have overlooked something,
17765 * so I'm not converting it until I get an EISA board to
17766 * test with.
17767 */
17768 inw(ioport + 4);
17769 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f361152007-07-30 08:04:53 -060017770 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017771 err = 0;
Matthew Wilcox71f361152007-07-30 08:04:53 -060017772 } else {
17773 release_region(ioport, ASC_IOADR_GAP);
17774 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017775 }
17776
17777 if (err) {
17778 kfree(data);
17779 } else {
17780 dev_set_drvdata(dev, data);
17781 }
17782
17783 fail:
17784 return err;
17785}
17786
17787static __devexit int advansys_eisa_remove(struct device *dev)
17788{
17789 int i;
17790 struct eisa_scsi_data *data = dev_get_drvdata(dev);
17791
17792 for (i = 0; i < 2; i++) {
Matthew Wilcox71f361152007-07-30 08:04:53 -060017793 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017794 struct Scsi_Host *shost = data->host[i];
17795 if (!shost)
17796 continue;
Matthew Wilcox71f361152007-07-30 08:04:53 -060017797 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017798 advansys_release(shost);
Matthew Wilcox71f361152007-07-30 08:04:53 -060017799 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017800 }
17801
17802 kfree(data);
17803 return 0;
17804}
17805
17806static struct eisa_driver advansys_eisa_driver = {
17807 .id_table = advansys_eisa_table,
17808 .driver = {
17809 .name = "advansys",
17810 .probe = advansys_eisa_probe,
17811 .remove = __devexit_p(advansys_eisa_remove),
17812 }
17813};
17814
Dave Jones2672ea82006-08-02 17:11:49 -040017815/* PCI Devices supported by this driver */
17816static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017817 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
17818 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17819 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
17820 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17821 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
17822 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17823 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
17824 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17825 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
17826 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17827 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
17828 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17829 {}
Dave Jones2672ea82006-08-02 17:11:49 -040017830};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017831
Dave Jones2672ea82006-08-02 17:11:49 -040017832MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017833
Matthew Wilcox9649af32007-07-26 21:51:47 -060017834static void __devinit advansys_set_latency(struct pci_dev *pdev)
17835{
17836 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
17837 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
17838 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
17839 } else {
17840 u8 latency;
17841 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
17842 if (latency < 0x20)
17843 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
17844 }
17845}
17846
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017847static int __devinit
17848advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
17849{
17850 int err, ioport;
17851 struct Scsi_Host *shost;
17852
17853 err = pci_enable_device(pdev);
17854 if (err)
17855 goto fail;
Matthew Wilcox71f361152007-07-30 08:04:53 -060017856 err = pci_request_regions(pdev, "advansys");
17857 if (err)
17858 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060017859 pci_set_master(pdev);
17860 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017861
17862 if (pci_resource_len(pdev, 0) == 0)
17863 goto nodev;
17864
17865 ioport = pci_resource_start(pdev, 0);
17866 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
17867
17868 if (!shost)
17869 goto nodev;
17870
17871 pci_set_drvdata(pdev, shost);
17872 return 0;
17873
17874 nodev:
17875 err = -ENODEV;
Matthew Wilcox71f361152007-07-30 08:04:53 -060017876 pci_release_regions(pdev);
17877 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017878 pci_disable_device(pdev);
17879 fail:
17880 return err;
17881}
17882
17883static void __devexit advansys_pci_remove(struct pci_dev *pdev)
17884{
17885 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f361152007-07-30 08:04:53 -060017886 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017887 pci_disable_device(pdev);
17888}
17889
17890static struct pci_driver advansys_pci_driver = {
17891 .name = "advansys",
17892 .id_table = advansys_pci_tbl,
17893 .probe = advansys_pci_probe,
17894 .remove = __devexit_p(advansys_pci_remove),
17895};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040017896
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017897static int __init advansys_init(void)
17898{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017899 int error;
17900
17901 error = isa_register_driver(&advansys_isa_driver,
17902 ASC_IOADR_TABLE_MAX_IX);
17903 if (error)
17904 goto fail;
17905
17906 error = isa_register_driver(&advansys_vlb_driver,
17907 ASC_IOADR_TABLE_MAX_IX);
17908 if (error)
17909 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017910
17911 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017912 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017913 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017914
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017915 error = pci_register_driver(&advansys_pci_driver);
17916 if (error)
17917 goto unregister_eisa;
17918
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017919 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017920
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017921 unregister_eisa:
17922 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017923 unregister_vlb:
17924 isa_unregister_driver(&advansys_vlb_driver);
17925 unregister_isa:
17926 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017927 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017928 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017929}
17930
17931static void __exit advansys_exit(void)
17932{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017933 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017934 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017935 isa_unregister_driver(&advansys_vlb_driver);
17936 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017937}
17938
17939module_init(advansys_init);
17940module_exit(advansys_exit);
17941
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040017942MODULE_LICENSE("GPL");