blob: 986c52a7b95e86388716e960887663ca70496b8b [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/*
3171 * Default EEPROM Configuration structure defined in a_init.c.
3172 */
3173static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
3174static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
3175static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
3176
3177/*
3178 * DvcGetPhyAddr() flag arguments
3179 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003180#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
3181#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
3182#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
3183#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
3184#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
3185#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
3187/* Return the address that is aligned at the next doubleword >= to 'addr'. */
3188#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
3189#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
3190#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
3191
3192/*
3193 * Total contiguous memory needed for driver SG blocks.
3194 *
3195 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
3196 * number of scatter-gather elements the driver supports in a
3197 * single request.
3198 */
3199
3200#define ADV_SG_LIST_MAX_BYTE_SIZE \
3201 (sizeof(ADV_SG_BLOCK) * \
3202 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
3203
3204/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 * --- Driver Constants and Macros
3206 */
3207
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208/* Reference Scsi_Host hostdata */
3209#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
3210
3211/* asc_board_t flags */
3212#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003213#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214#define ASC_SELECT_QUEUE_DEPTHS 0x08
3215
3216#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
3217#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
3218
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003219#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003221#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
3223#ifdef CONFIG_PROC_FS
3224/* /proc/scsi/advansys/[0...] related definitions */
3225#define ASC_PRTBUF_SIZE 2048
3226#define ASC_PRTLINE_SIZE 160
3227
3228#define ASC_PRT_NEXT() \
3229 if (cp) { \
3230 totlen += len; \
3231 leftlen -= len; \
3232 if (leftlen == 0) { \
3233 return totlen; \
3234 } \
3235 cp += len; \
3236 }
3237#endif /* CONFIG_PROC_FS */
3238
3239/* Asc Library return codes */
3240#define ASC_TRUE 1
3241#define ASC_FALSE 0
3242#define ASC_NOERROR 1
3243#define ASC_BUSY 0
3244#define ASC_ERROR (-1)
3245
3246/* struct scsi_cmnd function return codes */
3247#define STATUS_BYTE(byte) (byte)
3248#define MSG_BYTE(byte) ((byte) << 8)
3249#define HOST_BYTE(byte) ((byte) << 16)
3250#define DRIVER_BYTE(byte) ((byte) << 24)
3251
3252/*
3253 * The following definitions and macros are OS independent interfaces to
3254 * the queue functions:
3255 * REQ - SCSI request structure
3256 * REQP - pointer to SCSI request structure
3257 * REQPTID(reqp) - reqp's target id
3258 * REQPNEXT(reqp) - reqp's next pointer
3259 * REQPNEXTP(reqp) - pointer to reqp's next pointer
3260 * REQPTIME(reqp) - reqp's time stamp value
3261 * REQTIMESTAMP() - system time stamp value
3262 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003263typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
3265#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
3266#define REQPTID(reqp) ((reqp)->device->id)
3267#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
3268#define REQTIMESTAMP() (jiffies)
3269
3270#define REQTIMESTAT(function, ascq, reqp, tid) \
3271{ \
3272 /*
3273 * If the request time stamp is less than the system time stamp, then \
3274 * maybe the system time stamp wrapped. Set the request time to zero.\
3275 */ \
3276 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
3277 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
3278 } else { \
3279 /* Indicate an error occurred with the assertion. */ \
3280 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
3281 REQPTIME(reqp) = 0; \
3282 } \
3283 /* Handle first minimum time case without external initialization. */ \
3284 if (((ascq)->q_tot_cnt[tid] == 1) || \
3285 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
3286 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
3287 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
3288 (function), (tid), (ascq)->q_min_tim[tid]); \
3289 } \
3290 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
3291 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
3292 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
3293 (function), tid, (ascq)->q_max_tim[tid]); \
3294 } \
3295 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
3296 /* Reset the time stamp field. */ \
3297 REQPTIME(reqp) = 0; \
3298}
3299
3300/* asc_enqueue() flags */
3301#define ASC_FRONT 1
3302#define ASC_BACK 2
3303
3304/* asc_dequeue_list() argument */
3305#define ASC_TID_ALL (-1)
3306
3307/* Return non-zero, if the queue is empty. */
3308#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
3309
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003311#define ASC_STATS(shost, counter)
3312#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003314#define ASC_STATS(shost, counter) \
3315 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003317#define ASC_STATS_ADD(shost, counter, count) \
3318 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319#endif /* ADVANSYS_STATS */
3320
3321#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
3322
3323/* If the result wraps when calculating tenths, return 0. */
3324#define ASC_TENTHS(num, den) \
3325 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
3326 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
3327
3328/*
3329 * Display a message to the console.
3330 */
3331#define ASC_PRINT(s) \
3332 { \
3333 printk("advansys: "); \
3334 printk(s); \
3335 }
3336
3337#define ASC_PRINT1(s, a1) \
3338 { \
3339 printk("advansys: "); \
3340 printk((s), (a1)); \
3341 }
3342
3343#define ASC_PRINT2(s, a1, a2) \
3344 { \
3345 printk("advansys: "); \
3346 printk((s), (a1), (a2)); \
3347 }
3348
3349#define ASC_PRINT3(s, a1, a2, a3) \
3350 { \
3351 printk("advansys: "); \
3352 printk((s), (a1), (a2), (a3)); \
3353 }
3354
3355#define ASC_PRINT4(s, a1, a2, a3, a4) \
3356 { \
3357 printk("advansys: "); \
3358 printk((s), (a1), (a2), (a3), (a4)); \
3359 }
3360
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361#ifndef ADVANSYS_DEBUG
3362
3363#define ASC_DBG(lvl, s)
3364#define ASC_DBG1(lvl, s, a1)
3365#define ASC_DBG2(lvl, s, a1, a2)
3366#define ASC_DBG3(lvl, s, a1, a2, a3)
3367#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
3368#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
3369#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
3370#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
3371#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3372#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
3373#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3374#define ASC_DBG_PRT_HEX(lvl, name, start, length)
3375#define ASC_DBG_PRT_CDB(lvl, cdb, len)
3376#define ASC_DBG_PRT_SENSE(lvl, sense, len)
3377#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
3378
3379#else /* ADVANSYS_DEBUG */
3380
3381/*
3382 * Debugging Message Levels:
3383 * 0: Errors Only
3384 * 1: High-Level Tracing
3385 * 2-N: Verbose Tracing
3386 */
3387
3388#define ASC_DBG(lvl, s) \
3389 { \
3390 if (asc_dbglvl >= (lvl)) { \
3391 printk(s); \
3392 } \
3393 }
3394
3395#define ASC_DBG1(lvl, s, a1) \
3396 { \
3397 if (asc_dbglvl >= (lvl)) { \
3398 printk((s), (a1)); \
3399 } \
3400 }
3401
3402#define ASC_DBG2(lvl, s, a1, a2) \
3403 { \
3404 if (asc_dbglvl >= (lvl)) { \
3405 printk((s), (a1), (a2)); \
3406 } \
3407 }
3408
3409#define ASC_DBG3(lvl, s, a1, a2, a3) \
3410 { \
3411 if (asc_dbglvl >= (lvl)) { \
3412 printk((s), (a1), (a2), (a3)); \
3413 } \
3414 }
3415
3416#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
3417 { \
3418 if (asc_dbglvl >= (lvl)) { \
3419 printk((s), (a1), (a2), (a3), (a4)); \
3420 } \
3421 }
3422
3423#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
3424 { \
3425 if (asc_dbglvl >= (lvl)) { \
3426 asc_prt_scsi_host(s); \
3427 } \
3428 }
3429
3430#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
3431 { \
3432 if (asc_dbglvl >= (lvl)) { \
3433 asc_prt_scsi_cmnd(s); \
3434 } \
3435 }
3436
3437#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
3438 { \
3439 if (asc_dbglvl >= (lvl)) { \
3440 asc_prt_asc_scsi_q(scsiqp); \
3441 } \
3442 }
3443
3444#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
3445 { \
3446 if (asc_dbglvl >= (lvl)) { \
3447 asc_prt_asc_qdone_info(qdone); \
3448 } \
3449 }
3450
3451#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
3452 { \
3453 if (asc_dbglvl >= (lvl)) { \
3454 asc_prt_adv_scsi_req_q(scsiqp); \
3455 } \
3456 }
3457
3458#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
3459 { \
3460 if (asc_dbglvl >= (lvl)) { \
3461 asc_prt_hex((name), (start), (length)); \
3462 } \
3463 }
3464
3465#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
3466 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
3467
3468#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
3469 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
3470
3471#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
3472 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
3473#endif /* ADVANSYS_DEBUG */
3474
3475#ifndef ADVANSYS_ASSERT
3476#define ASC_ASSERT(a)
3477#else /* ADVANSYS_ASSERT */
3478
3479#define ASC_ASSERT(a) \
3480 { \
3481 if (!(a)) { \
3482 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
3483 __FILE__, __LINE__); \
3484 } \
3485 }
3486
3487#endif /* ADVANSYS_ASSERT */
3488
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489/*
3490 * --- Driver Structures
3491 */
3492
3493#ifdef ADVANSYS_STATS
3494
3495/* Per board statistics structure */
3496struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003497 /* Driver Entrypoint Statistics */
3498 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
3499 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
3500 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
3501 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
3502 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
3503 ADV_DCNT done; /* # calls to request's scsi_done function */
3504 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
3505 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
3506 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
3507 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
3508 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
3509 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
3510 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
3511 ADV_DCNT exe_unknown; /* # unknown returns. */
3512 /* Data Transfer Statistics */
3513 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
3514 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
3515 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
3516 ADV_DCNT sg_elem; /* # scatter-gather elements */
3517 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518};
3519#endif /* ADVANSYS_STATS */
3520
3521/*
3522 * Request queuing structure
3523 */
3524typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003525 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
3526 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
3527 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003529 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
3530 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
3531 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
3532 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
3533 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
3534 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
3535#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536} asc_queue_t;
3537
3538/*
3539 * Adv Library Request Structures
3540 *
3541 * The following two structures are used to process Wide Board requests.
3542 *
3543 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
3544 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
3545 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
3546 * Mid-Level SCSI request structure.
3547 *
3548 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
3549 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
3550 * up to 255 scatter-gather elements may be used per request or
3551 * ADV_SCSI_REQ_Q.
3552 *
3553 * Both structures must be 32 byte aligned.
3554 */
3555typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003556 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
3557 uchar align[32]; /* Sgblock structure padding. */
3558 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559} adv_sgblk_t;
3560
3561typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003562 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
3563 uchar align[32]; /* Request structure padding. */
3564 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
3565 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
3566 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567} adv_req_t;
3568
3569/*
3570 * Structure allocated for each board.
3571 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003572 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 * of the 'Scsi_Host' structure starting at the 'hostdata'
3574 * field. It is guaranteed to be allocated from DMA-able memory.
3575 */
3576typedef struct asc_board {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04003577 struct device *dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003578 int id; /* Board Id */
3579 uint flags; /* Board flags */
3580 union {
3581 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
3582 ADV_DVC_VAR adv_dvc_var; /* Wide board */
3583 } dvc_var;
3584 union {
3585 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
3586 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
3587 } dvc_cfg;
3588 ushort asc_n_io_port; /* Number I/O ports. */
3589 asc_queue_t active; /* Active command queue */
3590 asc_queue_t waiting; /* Waiting command queue */
3591 asc_queue_t done; /* Done command queue */
3592 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
3593 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
3594 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
3595 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
3596 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
3597 union {
3598 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
3599 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
3600 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
3601 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
3602 } eep_config;
3603 ulong last_reset; /* Saved last reset time */
3604 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003605 /* /proc/scsi/advansys/[0...] */
3606 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003608 struct asc_stats asc_stats; /* Board statistics */
3609#endif /* ADVANSYS_STATS */
3610 /*
3611 * The following fields are used only for Narrow Boards.
3612 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003613 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3614 /*
3615 * The following fields are used only for Wide Boards.
3616 */
3617 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3618 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06003619 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003620 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3621 adv_req_t *adv_reqp; /* Request structures. */
3622 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3623 ushort bios_signature; /* BIOS Signature. */
3624 ushort bios_version; /* BIOS Version. */
3625 ushort bios_codeseg; /* BIOS Code Segment. */
3626 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627} asc_board_t;
3628
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06003629#define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \
3630 dvc_var.adv_dvc_var)
3631#define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev)
3632
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06003634static int asc_board_count;
3635
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003637static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638
3639/*
3640 * Global structures required to issue a command.
3641 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003642static ASC_SCSI_Q asc_scsi_q = { {0} };
3643static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003646static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003647#endif /* ADVANSYS_DEBUG */
3648
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649/*
3650 * --- Driver Function Prototypes
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 */
3652
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003653static int advansys_slave_configure(struct scsi_device *);
3654static void asc_scsi_done_list(struct scsi_cmnd *);
3655static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3656static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3657static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3658static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003659static void asc_enqueue(asc_queue_t *, REQP, int);
3660static REQP asc_dequeue(asc_queue_t *, int);
3661static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3662static int asc_rmqueue(asc_queue_t *, REQP);
3663static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003665static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3666static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3667static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3668static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3669static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3670static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3671static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3672static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3673static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3674static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675#endif /* CONFIG_PROC_FS */
3676
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677/* Statistics function prototypes. */
3678#ifdef ADVANSYS_STATS
3679#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003680static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3681static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682#endif /* CONFIG_PROC_FS */
3683#endif /* ADVANSYS_STATS */
3684
3685/* Debug function prototypes. */
3686#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003687static void asc_prt_scsi_host(struct Scsi_Host *);
3688static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
3689static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
3690static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
3691static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
3692static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
3693static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
3694static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
3695static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
3696static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
3697static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698#endif /* ADVANSYS_DEBUG */
3699
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700#ifdef CONFIG_PROC_FS
3701/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06003702 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 *
3704 * *buffer: I/O buffer
3705 * **start: if inout == FALSE pointer into buffer where user read should start
3706 * offset: current offset into a /proc/scsi/advansys/[0...] file
3707 * length: length of buffer
3708 * hostno: Scsi_Host host_no
3709 * inout: TRUE - user is writing; FALSE - user is reading
3710 *
3711 * Return the number of bytes read from or written to a
3712 * /proc/scsi/advansys/[0...] file.
3713 *
3714 * Note: This function uses the per board buffer 'prtbuf' which is
3715 * allocated when the board is initialized in advansys_detect(). The
3716 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
3717 * used to write to the buffer. The way asc_proc_copy() is written
3718 * if 'prtbuf' is too small it will not be overwritten. Instead the
3719 * user just won't get all the available statistics.
3720 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003721static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003723 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003725 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003726 char *cp;
3727 int cplen;
3728 int cnt;
3729 int totcnt;
3730 int leftlen;
3731 char *curbuf;
3732 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003734 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735#endif /* ADVANSYS_STATS */
3736
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003737 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003739 /*
3740 * User write not supported.
3741 */
3742 if (inout == TRUE) {
3743 return (-ENOSYS);
3744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003746 /*
3747 * User read of /proc/scsi/advansys/[0...] file.
3748 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749
Matthew Wilcox2a437952007-07-26 11:00:51 -04003750 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003752 /* Copy read data starting at the beginning of the buffer. */
3753 *start = buffer;
3754 curbuf = buffer;
3755 advoffset = 0;
3756 totcnt = 0;
3757 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003759 /*
3760 * Get board configuration information.
3761 *
3762 * advansys_info() returns the board string from its own static buffer.
3763 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04003764 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003765 strcat(cp, "\n");
3766 cplen = strlen(cp);
3767 /* Copy board information. */
3768 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3769 totcnt += cnt;
3770 leftlen -= cnt;
3771 if (leftlen == 0) {
3772 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3773 return totcnt;
3774 }
3775 advoffset += cplen;
3776 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003778 /*
3779 * Display Wide Board BIOS Information.
3780 */
3781 if (ASC_WIDE_BOARD(boardp)) {
3782 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003783 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003784 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003785 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003786 cplen);
3787 totcnt += cnt;
3788 leftlen -= cnt;
3789 if (leftlen == 0) {
3790 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3791 return totcnt;
3792 }
3793 advoffset += cplen;
3794 curbuf += cnt;
3795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003797 /*
3798 * Display driver information for each device attached to the board.
3799 */
3800 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003801 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003802 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3803 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3804 totcnt += cnt;
3805 leftlen -= cnt;
3806 if (leftlen == 0) {
3807 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3808 return totcnt;
3809 }
3810 advoffset += cplen;
3811 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003813 /*
3814 * Display EEPROM configuration for the board.
3815 */
3816 cp = boardp->prtbuf;
3817 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003818 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003819 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003820 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003821 }
3822 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3823 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3824 totcnt += cnt;
3825 leftlen -= cnt;
3826 if (leftlen == 0) {
3827 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3828 return totcnt;
3829 }
3830 advoffset += cplen;
3831 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003833 /*
3834 * Display driver configuration and information for the board.
3835 */
3836 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003837 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003838 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3839 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3840 totcnt += cnt;
3841 leftlen -= cnt;
3842 if (leftlen == 0) {
3843 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3844 return totcnt;
3845 }
3846 advoffset += cplen;
3847 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848
3849#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003850 /*
3851 * Display driver statistics for the board.
3852 */
3853 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003854 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003855 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
3856 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3857 totcnt += cnt;
3858 leftlen -= cnt;
3859 if (leftlen == 0) {
3860 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3861 return totcnt;
3862 }
3863 advoffset += cplen;
3864 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003866 /*
3867 * Display driver statistics for each target.
3868 */
3869 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
3870 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003871 cplen = asc_prt_target_stats(shost, tgt_id, cp,
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003872 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003873 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003874 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
3875 cplen);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003876 totcnt += cnt;
3877 leftlen -= cnt;
3878 if (leftlen == 0) {
3879 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3880 return totcnt;
3881 }
3882 advoffset += cplen;
3883 curbuf += cnt;
3884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885#endif /* ADVANSYS_STATS */
3886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003887 /*
3888 * Display Asc Library dynamic configuration information
3889 * for the board.
3890 */
3891 cp = boardp->prtbuf;
3892 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003893 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003894 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003895 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003896 }
3897 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3898 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3899 totcnt += cnt;
3900 leftlen -= cnt;
3901 if (leftlen == 0) {
3902 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3903 return totcnt;
3904 }
3905 advoffset += cplen;
3906 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003908 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003910 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911}
3912#endif /* CONFIG_PROC_FS */
3913
3914/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 * advansys_info()
3916 *
3917 * Return suitable for printing on the console with the argument
3918 * adapter's configuration information.
3919 *
3920 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
3921 * otherwise the static 'info' array will be overrun.
3922 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003923static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003925 static char info[ASC_INFO_SIZE];
3926 asc_board_t *boardp;
3927 ASC_DVC_VAR *asc_dvc_varp;
3928 ADV_DVC_VAR *adv_dvc_varp;
3929 char *busname;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003930 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003932 boardp = ASC_BOARDP(shost);
3933 if (ASC_NARROW_BOARD(boardp)) {
3934 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
3935 ASC_DBG(1, "advansys_info: begin\n");
3936 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
3937 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
3938 ASC_IS_ISAPNP) {
3939 busname = "ISA PnP";
3940 } else {
3941 busname = "ISA";
3942 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003943 sprintf(info,
3944 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
3945 ASC_VERSION, busname,
3946 (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003947 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3948 shost->irq, shost->dma_channel);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003949 } else {
3950 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
3951 busname = "VL";
3952 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
3953 busname = "EISA";
3954 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
3955 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
3956 == ASC_IS_PCI_ULTRA) {
3957 busname = "PCI Ultra";
3958 } else {
3959 busname = "PCI";
3960 }
3961 } else {
3962 busname = "?";
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003963 ASC_PRINT2("advansys_info: board %d: unknown "
3964 "bus type %d\n", boardp->id,
3965 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003966 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003967 sprintf(info,
3968 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
Matthew Wilcoxecec1942007-07-30 08:08:22 -06003969 ASC_VERSION, busname, (ulong)shost->io_port,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003970 (ulong)shost->io_port + ASC_IOADR_GAP - 1,
3971 shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003972 }
3973 } else {
3974 /*
3975 * Wide Adapter Information
3976 *
3977 * Memory-mapped I/O is used instead of I/O space to access
3978 * the adapter, but display the I/O Port range. The Memory
3979 * I/O address is displayed through the driver /proc file.
3980 */
3981 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
3982 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003983 widename = "Ultra-Wide";
3984 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003985 widename = "Ultra2-Wide";
3986 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003987 widename = "Ultra3-Wide";
3988 }
3989 sprintf(info,
3990 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
3991 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04003992 (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, shost->irq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003993 }
3994 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
3995 ASC_DBG(1, "advansys_info: end\n");
3996 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997}
3998
3999/*
4000 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
4001 *
4002 * This function always returns 0. Command return status is saved
4003 * in the 'scp' result field.
4004 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004005static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004006advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004008 struct Scsi_Host *shost;
4009 asc_board_t *boardp;
4010 ulong flags;
4011 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004013 shost = scp->device->host;
4014 boardp = ASC_BOARDP(shost);
4015 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004017 /* host_lock taken by mid-level prior to call but need to protect */
4018 /* against own ISR */
4019 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004021 /*
4022 * Block new commands while handling a reset or abort request.
4023 */
4024 if (boardp->flags & ASC_HOST_IN_RESET) {
4025 ASC_DBG1(1,
4026 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4027 (ulong)scp);
4028 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004030 /*
4031 * Add blocked requests to the board's 'done' queue. The queued
4032 * requests will be completed at the end of the abort or reset
4033 * handling.
4034 */
4035 asc_enqueue(&boardp->done, scp, ASC_BACK);
4036 spin_unlock_irqrestore(&boardp->lock, flags);
4037 return 0;
4038 }
4039
4040 /*
4041 * Attempt to execute any waiting commands for the board.
4042 */
4043 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4044 ASC_DBG(1,
4045 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4046 asc_execute_queue(&boardp->waiting);
4047 }
4048
4049 /*
4050 * Save the function pointer to Linux mid-level 'done' function
4051 * and attempt to execute the command.
4052 *
4053 * If ASC_NOERROR is returned the request has been added to the
4054 * board's 'active' queue and will be completed by the interrupt
4055 * handler.
4056 *
4057 * If ASC_BUSY is returned add the request to the board's per
4058 * target waiting list. This is the first time the request has
4059 * been tried. Add it to the back of the waiting list. It will be
4060 * retried later.
4061 *
4062 * If an error occurred, the request will have been placed on the
4063 * board's 'done' queue and must be completed before returning.
4064 */
4065 scp->scsi_done = done;
4066 switch (asc_execute_scsi_cmnd(scp)) {
4067 case ASC_NOERROR:
4068 break;
4069 case ASC_BUSY:
4070 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4071 break;
4072 case ASC_ERROR:
4073 default:
4074 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4075 /* Interrupts could be enabled here. */
4076 asc_scsi_done_list(done_scp);
4077 break;
4078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004081 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082}
4083
4084/*
4085 * advansys_reset()
4086 *
4087 * Reset the bus associated with the command 'scp'.
4088 *
4089 * This function runs its own thread. Interrupts must be blocked but
4090 * sleeping is allowed and no locking other than for host structures is
4091 * required. Returns SUCCESS or FAILED.
4092 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004093static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004095 struct Scsi_Host *shost;
4096 asc_board_t *boardp;
4097 ASC_DVC_VAR *asc_dvc_varp;
4098 ADV_DVC_VAR *adv_dvc_varp;
4099 ulong flags;
4100 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4101 struct scsi_cmnd *tscp, *new_last_scp;
4102 int status;
4103 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004105 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106
4107#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004108 if (scp->device->host != NULL) {
4109 ASC_STATS(scp->device->host, reset);
4110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111#endif /* ADVANSYS_STATS */
4112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004113 if ((shost = scp->device->host) == NULL) {
4114 scp->result = HOST_BYTE(DID_ERROR);
4115 return FAILED;
4116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004118 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004120 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4121 boardp->id);
4122 /*
4123 * Check for re-entrancy.
4124 */
4125 spin_lock_irqsave(&boardp->lock, flags);
4126 if (boardp->flags & ASC_HOST_IN_RESET) {
4127 spin_unlock_irqrestore(&boardp->lock, flags);
4128 return FAILED;
4129 }
4130 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004133 if (ASC_NARROW_BOARD(boardp)) {
4134 /*
4135 * Narrow Board
4136 */
4137 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004139 /*
4140 * Reset the chip and SCSI bus.
4141 */
4142 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4143 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004145 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4146 if (asc_dvc_varp->err_code) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004147 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4148 "error: 0x%x\n", boardp->id,
4149 asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004150 ret = FAILED;
4151 } else if (status) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004152 ASC_PRINT2("advansys_reset: board %d: SCSI bus reset "
4153 "warning: 0x%x\n", boardp->id, status);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004154 } else {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004155 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4156 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004159 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4160 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004162 } else {
4163 /*
4164 * Wide Board
4165 *
4166 * If the suggest reset bus flags are set, then reset the bus.
4167 * Otherwise only reset the device.
4168 */
4169 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004171 /*
4172 * Reset the target's SCSI bus.
4173 */
4174 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4175 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4176 case ASC_TRUE:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004177 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4178 "successful.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004179 break;
4180 case ASC_FALSE:
4181 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004182 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset "
4183 "error.\n", boardp->id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004184 ret = FAILED;
4185 break;
4186 }
4187 spin_lock_irqsave(&boardp->lock, flags);
4188 (void)AdvISR(adv_dvc_varp);
4189 }
4190 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004192 /*
4193 * Dequeue all board 'done' requests. A pointer to the last request
4194 * is returned in 'last_scp'.
4195 */
4196 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004198 /*
4199 * Dequeue all board 'active' requests for all devices and set
4200 * the request status to DID_RESET. A pointer to the last request
4201 * is returned in 'last_scp'.
4202 */
4203 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004204 done_scp = asc_dequeue_list(&boardp->active, &last_scp,
4205 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004206 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4207 tscp->result = HOST_BYTE(DID_RESET);
4208 }
4209 } else {
4210 /* Append to 'done_scp' at the end with 'last_scp'. */
4211 ASC_ASSERT(last_scp != NULL);
4212 last_scp->host_scribble =
4213 (unsigned char *)asc_dequeue_list(&boardp->active,
4214 &new_last_scp,
4215 ASC_TID_ALL);
4216 if (new_last_scp != NULL) {
4217 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4218 for (tscp = REQPNEXT(last_scp); tscp;
4219 tscp = REQPNEXT(tscp)) {
4220 tscp->result = HOST_BYTE(DID_RESET);
4221 }
4222 last_scp = new_last_scp;
4223 }
4224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004226 /*
4227 * Dequeue all 'waiting' requests and set the request status
4228 * to DID_RESET.
4229 */
4230 if (done_scp == NULL) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004231 done_scp = asc_dequeue_list(&boardp->waiting, &last_scp,
4232 ASC_TID_ALL);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004233 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4234 tscp->result = HOST_BYTE(DID_RESET);
4235 }
4236 } else {
4237 /* Append to 'done_scp' at the end with 'last_scp'. */
4238 ASC_ASSERT(last_scp != NULL);
4239 last_scp->host_scribble =
4240 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4241 &new_last_scp,
4242 ASC_TID_ALL);
4243 if (new_last_scp != NULL) {
4244 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4245 for (tscp = REQPNEXT(last_scp); tscp;
4246 tscp = REQPNEXT(tscp)) {
4247 tscp->result = HOST_BYTE(DID_RESET);
4248 }
4249 last_scp = new_last_scp;
4250 }
4251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004253 /* Save the time of the most recently completed reset. */
4254 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004256 /* Clear reset flag. */
4257 boardp->flags &= ~ASC_HOST_IN_RESET;
4258 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004260 /*
4261 * Complete all the 'done_scp' requests.
4262 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004263 if (done_scp)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004264 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004266 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004268 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269}
4270
4271/*
4272 * advansys_biosparam()
4273 *
4274 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4275 * support is enabled for a drive.
4276 *
4277 * ip (information pointer) is an int array with the following definition:
4278 * ip[0]: heads
4279 * ip[1]: sectors
4280 * ip[2]: cylinders
4281 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004282static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004284 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004286 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004288 ASC_DBG(1, "advansys_biosparam: begin\n");
4289 ASC_STATS(sdev->host, biosparam);
4290 boardp = ASC_BOARDP(sdev->host);
4291 if (ASC_NARROW_BOARD(boardp)) {
4292 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4293 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4294 ip[0] = 255;
4295 ip[1] = 63;
4296 } else {
4297 ip[0] = 64;
4298 ip[1] = 32;
4299 }
4300 } else {
4301 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4302 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4303 ip[0] = 255;
4304 ip[1] = 63;
4305 } else {
4306 ip[0] = 64;
4307 ip[1] = 32;
4308 }
4309 }
4310 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4311 ASC_DBG(1, "advansys_biosparam: end\n");
4312 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313}
4314
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004315static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004316 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004318 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004320 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004321 .info = advansys_info,
4322 .queuecommand = advansys_queuecommand,
4323 .eh_bus_reset_handler = advansys_reset,
4324 .bios_param = advansys_biosparam,
4325 .slave_configure = advansys_slave_configure,
4326 /*
4327 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004328 * must be set. The flag will be cleared in advansys_board_found
4329 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004330 */
4331 .unchecked_isa_dma = 1,
4332 /*
4333 * All adapters controlled by this driver are capable of large
4334 * scatter-gather lists. According to the mid-level SCSI documentation
4335 * this obviates any performance gain provided by setting
4336 * 'use_clustering'. But empirically while CPU utilization is increased
4337 * by enabling clustering, I/O throughput increases as well.
4338 */
4339 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342/*
4343 * --- Miscellaneous Driver Functions
4344 */
4345
4346/*
4347 * First-level interrupt handler.
4348 *
4349 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4350 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4351 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4352 * to the AdvanSys driver which is for a device sharing an interrupt with
4353 * an AdvanSys adapter.
4354 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004355static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004357 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004358 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4359 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004360 struct Scsi_Host *shost = dev_id;
4361 asc_board_t *boardp = ASC_BOARDP(shost);
4362 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004364 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
4365 spin_lock_irqsave(&boardp->lock, flags);
4366 if (ASC_NARROW_BOARD(boardp)) {
4367 /*
4368 * Narrow Board
4369 */
4370 if (AscIsIntPending(shost->io_port)) {
4371 result = IRQ_HANDLED;
4372 ASC_STATS(shost, interrupt);
4373 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
4374 AscISR(&boardp->dvc_var.asc_dvc_var);
4375 }
4376 } else {
4377 /*
4378 * Wide Board
4379 */
4380 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4381 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4382 result = IRQ_HANDLED;
4383 ASC_STATS(shost, interrupt);
4384 }
4385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004387 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004388 * Start waiting requests and create a list of completed requests.
4389 *
4390 * If a reset request is being performed for the board, the reset
4391 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004392 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004393 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4394 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
4395 "last_scp 0x%p\n", done_scp, last_scp);
4396
4397 /* Start any waiting commands for the board. */
4398 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4399 ASC_DBG(1, "advansys_interrupt: before "
4400 "asc_execute_queue()\n");
4401 asc_execute_queue(&boardp->waiting);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004404 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004405 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004406 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004407 * 'done_scp' will always be NULL on the first iteration of
4408 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004409 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004410 if (done_scp == NULL) {
4411 done_scp = asc_dequeue_list(&boardp->done,
4412 &last_scp, ASC_TID_ALL);
4413 } else {
4414 ASC_ASSERT(last_scp != NULL);
4415 last_scp->host_scribble =
4416 (unsigned char *)asc_dequeue_list(&boardp->
4417 done,
4418 &new_last_scp,
4419 ASC_TID_ALL);
4420 if (new_last_scp != NULL) {
4421 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4422 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004423 }
4424 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004425 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004426 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004428 /*
4429 * If interrupts were enabled on entry, then they
4430 * are now enabled here.
4431 *
4432 * Complete all requests on the done list.
4433 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004435 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004437 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004438 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439}
4440
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004441static void
4442advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
4443{
4444 ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id;
4445 ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng;
4446
4447 if (sdev->lun == 0) {
4448 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr;
4449 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) {
4450 asc_dvc->init_sdtr |= tid_bit;
4451 } else {
4452 asc_dvc->init_sdtr &= ~tid_bit;
4453 }
4454
4455 if (orig_init_sdtr != asc_dvc->init_sdtr)
4456 AscAsyncFix(asc_dvc, sdev);
4457 }
4458
4459 if (sdev->tagged_supported) {
4460 if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) {
4461 if (sdev->lun == 0) {
4462 asc_dvc->cfg->can_tagged_qng |= tid_bit;
4463 asc_dvc->use_tagged_qng |= tid_bit;
4464 }
4465 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4466 asc_dvc->max_dvc_qng[sdev->id]);
4467 }
4468 } else {
4469 if (sdev->lun == 0) {
4470 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
4471 asc_dvc->use_tagged_qng &= ~tid_bit;
4472 }
4473 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4474 }
4475
4476 if ((sdev->lun == 0) &&
4477 (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) {
4478 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
4479 asc_dvc->cfg->disc_enable);
4480 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
4481 asc_dvc->use_tagged_qng);
4482 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
4483 asc_dvc->cfg->can_tagged_qng);
4484
4485 asc_dvc->max_dvc_qng[sdev->id] =
4486 asc_dvc->cfg->max_tag_qng[sdev->id];
4487 AscWriteLramByte(asc_dvc->iop_base,
4488 (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id),
4489 asc_dvc->max_dvc_qng[sdev->id]);
4490 }
4491}
4492
4493/*
4494 * Wide Transfers
4495 *
4496 * If the EEPROM enabled WDTR for the device and the device supports wide
4497 * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and
4498 * write the new value to the microcode.
4499 */
4500static void
4501advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask)
4502{
4503 unsigned short cfg_word;
4504 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4505 if ((cfg_word & tidmask) != 0)
4506 return;
4507
4508 cfg_word |= tidmask;
4509 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
4510
4511 /*
4512 * Clear the microcode SDTR and WDTR negotiation done indicators for
4513 * the target to cause it to negotiate with the new setting set above.
4514 * WDTR when accepted causes the target to enter asynchronous mode, so
4515 * SDTR must be negotiated.
4516 */
4517 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4518 cfg_word &= ~tidmask;
4519 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4520 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4521 cfg_word &= ~tidmask;
4522 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
4523}
4524
4525/*
4526 * Synchronous Transfers
4527 *
4528 * If the EEPROM enabled SDTR for the device and the device
4529 * supports synchronous transfers, then turn on the device's
4530 * 'sdtr_able' bit. Write the new value to the microcode.
4531 */
4532static void
4533advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask)
4534{
4535 unsigned short cfg_word;
4536 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4537 if ((cfg_word & tidmask) != 0)
4538 return;
4539
4540 cfg_word |= tidmask;
4541 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
4542
4543 /*
4544 * Clear the microcode "SDTR negotiation" done indicator for the
4545 * target to cause it to negotiate with the new setting set above.
4546 */
4547 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4548 cfg_word &= ~tidmask;
4549 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
4550}
4551
4552/*
4553 * PPR (Parallel Protocol Request) Capable
4554 *
4555 * If the device supports DT mode, then it must be PPR capable.
4556 * The PPR message will be used in place of the SDTR and WDTR
4557 * messages to negotiate synchronous speed and offset, transfer
4558 * width, and protocol options.
4559 */
4560static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc,
4561 AdvPortAddr iop_base, unsigned short tidmask)
4562{
4563 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4564 adv_dvc->ppr_able |= tidmask;
4565 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able);
4566}
4567
4568static void
4569advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
4570{
4571 AdvPortAddr iop_base = adv_dvc->iop_base;
4572 unsigned short tidmask = 1 << sdev->id;
4573
4574 if (sdev->lun == 0) {
4575 /*
4576 * Handle WDTR, SDTR, and Tag Queuing. If the feature
4577 * is enabled in the EEPROM and the device supports the
4578 * feature, then enable it in the microcode.
4579 */
4580
4581 if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr)
4582 advansys_wide_enable_wdtr(iop_base, tidmask);
4583 if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr)
4584 advansys_wide_enable_sdtr(iop_base, tidmask);
4585 if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr)
4586 advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask);
4587
4588 /*
4589 * Tag Queuing is disabled for the BIOS which runs in polled
4590 * mode and would see no benefit from Tag Queuing. Also by
4591 * disabling Tag Queuing in the BIOS devices with Tag Queuing
4592 * bugs will at least work with the BIOS.
4593 */
4594 if ((adv_dvc->tagqng_able & tidmask) &&
4595 sdev->tagged_supported) {
4596 unsigned short cfg_word;
4597 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
4598 cfg_word |= tidmask;
4599 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
4600 cfg_word);
4601 AdvWriteByteLram(iop_base,
4602 ASC_MC_NUMBER_OF_MAX_CMD + sdev->id,
4603 adv_dvc->max_dvc_qng);
4604 }
4605 }
4606
4607 if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
4608 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
4609 adv_dvc->max_dvc_qng);
4610 } else {
4611 scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
4612 }
4613}
4614
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615/*
4616 * Set the number of commands to queue per device for the
4617 * specified host adapter.
4618 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004619static int advansys_slave_configure(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620{
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004621 asc_board_t *boardp = ASC_BOARDP(sdev->host);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004622 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004623
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004624 /*
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004625 * Save a pointer to the sdev and set its initial/maximum
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004626 * queue depth. Only save the pointer for a lun0 dev though.
4627 */
Matthew Wilcox47d853c2007-07-26 11:41:33 -04004628 if (sdev->lun == 0)
4629 boardp->device[sdev->id] = sdev;
4630
4631 if (ASC_NARROW_BOARD(boardp))
4632 advansys_narrow_slave_configure(sdev,
4633 &boardp->dvc_var.asc_dvc_var);
4634 else
4635 advansys_wide_slave_configure(sdev,
4636 &boardp->dvc_var.adv_dvc_var);
4637
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004638 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639}
4640
4641/*
4642 * Complete all requests on the singly linked list pointed
4643 * to by 'scp'.
4644 *
4645 * Interrupts can be enabled on entry.
4646 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004647static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004649 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004651 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4652 while (scp != NULL) {
4653 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004655 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4656 tscp = REQPNEXT(scp);
4657 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004659 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004661 if (scp->use_sg)
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004662 dma_unmap_sg(boardp->dev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004663 (struct scatterlist *)scp->request_buffer,
4664 scp->use_sg, scp->sc_data_direction);
4665 else if (scp->request_bufflen)
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004666 dma_unmap_single(boardp->dev, scp->SCp.dma_handle,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004667 scp->request_bufflen,
4668 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004670 ASC_STATS(scp->device->host, done);
4671 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004673 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004675 scp = tscp;
4676 }
4677 ASC_DBG(2, "asc_scsi_done_list: done\n");
4678 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679}
4680
4681/*
4682 * Execute a single 'Scsi_Cmnd'.
4683 *
4684 * The function 'done' is called when the request has been completed.
4685 *
4686 * Scsi_Cmnd:
4687 *
4688 * host - board controlling device
4689 * device - device to send command
4690 * target - target of device
4691 * lun - lun of device
4692 * cmd_len - length of SCSI CDB
4693 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4694 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4695 *
4696 * if (use_sg == 0) {
4697 * request_buffer - buffer address for request
4698 * request_bufflen - length of request buffer
4699 * } else {
4700 * request_buffer - pointer to scatterlist structure
4701 * }
4702 *
4703 * sense_buffer - sense command buffer
4704 *
4705 * result (4 bytes of an int):
4706 * Byte Meaning
4707 * 0 SCSI Status Byte Code
4708 * 1 SCSI One Byte Message Code
4709 * 2 Host Error Code
4710 * 3 Mid-Level Error Code
4711 *
4712 * host driver fields:
4713 * SCp - Scsi_Pointer used for command processing status
4714 * scsi_done - used to save caller's done function
4715 * host_scribble - used for pointer to another struct scsi_cmnd
4716 *
4717 * If this function returns ASC_NOERROR the request has been enqueued
4718 * on the board's 'active' queue and will be completed from the
4719 * interrupt handler.
4720 *
4721 * If this function returns ASC_NOERROR the request has been enqueued
4722 * on the board's 'done' queue and must be completed by the caller.
4723 *
4724 * If ASC_BUSY is returned the request will be enqueued by the
4725 * caller on the target's waiting queue and re-tried later.
4726 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004727static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004729 asc_board_t *boardp;
4730 ASC_DVC_VAR *asc_dvc_varp;
4731 ADV_DVC_VAR *adv_dvc_varp;
4732 ADV_SCSI_REQ_Q *adv_scsiqp;
4733 struct scsi_device *device;
4734 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004736 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4737 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004739 boardp = ASC_BOARDP(scp->device->host);
4740 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004742 if (ASC_NARROW_BOARD(boardp)) {
4743 /*
4744 * Build and execute Narrow Board request.
4745 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004747 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004749 /*
4750 * Build Asc Library request structure using the
4751 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4752 *
4753 * If an error is returned, then the request has been
4754 * queued on the board done queue. It will be completed
4755 * by the caller.
4756 *
4757 * asc_build_req() can not return ASC_BUSY.
4758 */
4759 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4760 ASC_STATS(scp->device->host, build_error);
4761 return ASC_ERROR;
4762 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004764 /*
4765 * Execute the command. If there is no error, add the command
4766 * to the active queue.
4767 */
4768 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4769 case ASC_NOERROR:
4770 ASC_STATS(scp->device->host, exe_noerror);
4771 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004772 * Increment monotonically increasing per device
4773 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004774 */
4775 boardp->reqcnt[scp->device->id]++;
4776 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004777 ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), "
4778 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004779 break;
4780 case ASC_BUSY:
4781 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004782 * Caller will enqueue request on the target's waiting
4783 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004784 */
4785 ASC_STATS(scp->device->host, exe_busy);
4786 break;
4787 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004788 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4789 "AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4790 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004791 ASC_STATS(scp->device->host, exe_error);
4792 scp->result = HOST_BYTE(DID_ERROR);
4793 asc_enqueue(&boardp->done, scp, ASC_BACK);
4794 break;
4795 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004796 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4797 "AscExeScsiQueue() unknown, err_code 0x%x\n",
4798 boardp->id, asc_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004799 ASC_STATS(scp->device->host, exe_unknown);
4800 scp->result = HOST_BYTE(DID_ERROR);
4801 asc_enqueue(&boardp->done, scp, ASC_BACK);
4802 break;
4803 }
4804 } else {
4805 /*
4806 * Build and execute Wide Board request.
4807 */
4808 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004810 /*
4811 * Build and get a pointer to an Adv Library request structure.
4812 *
4813 * If the request is successfully built then send it below,
4814 * otherwise return with an error.
4815 */
4816 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4817 case ASC_NOERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004818 ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req "
4819 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004820 break;
4821 case ASC_BUSY:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004822 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4823 "ASC_BUSY\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004824 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004825 * If busy is returned the request has not been
4826 * enqueued. It will be enqueued by the caller on the
4827 * target's waiting queue and retried later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004828 *
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004829 * The asc_stats fields 'adv_build_noreq' and
4830 * 'adv_build_nosg' count wide board busy conditions.
4831 * They are updated in adv_build_req and
4832 * adv_get_sglist, respectively.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004833 */
4834 return ASC_BUSY;
4835 case ASC_ERROR:
4836 /*
4837 * If an error is returned, then the request has been
4838 * queued on the board done queue. It will be completed
4839 * by the caller.
4840 */
4841 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004842 ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req "
4843 "ASC_ERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004844 ASC_STATS(scp->device->host, build_error);
4845 return ASC_ERROR;
4846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004848 /*
4849 * Execute the command. If there is no error, add the command
4850 * to the active queue.
4851 */
4852 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
4853 case ASC_NOERROR:
4854 ASC_STATS(scp->device->host, exe_noerror);
4855 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004856 * Increment monotonically increasing per device
4857 * successful request counter. Wrapping doesn't matter.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004858 */
4859 boardp->reqcnt[scp->device->id]++;
4860 asc_enqueue(&boardp->active, scp, ASC_BACK);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004861 ASC_DBG(1, "asc_execute_scsi_cmnd: AdvExeScsiQueue(), "
4862 "ASC_NOERROR\n");
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004863 break;
4864 case ASC_BUSY:
4865 /*
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004866 * Caller will enqueue request on the target's waiting
4867 * queue and retry later.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004868 */
4869 ASC_STATS(scp->device->host, exe_busy);
4870 break;
4871 case ASC_ERROR:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004872 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4873 "AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4874 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004875 ASC_STATS(scp->device->host, exe_error);
4876 scp->result = HOST_BYTE(DID_ERROR);
4877 asc_enqueue(&boardp->done, scp, ASC_BACK);
4878 break;
4879 default:
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004880 ASC_PRINT2("asc_execute_scsi_cmnd: board %d: "
4881 "AdvExeScsiQueue() unknown, err_code 0x%x\n",
4882 boardp->id, adv_dvc_varp->err_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004883 ASC_STATS(scp->device->host, exe_unknown);
4884 scp->result = HOST_BYTE(DID_ERROR);
4885 asc_enqueue(&boardp->done, scp, ASC_BACK);
4886 break;
4887 }
4888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004890 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
4891 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892}
4893
4894/*
4895 * Build a request structure for the Asc Library (Narrow Board).
4896 *
4897 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
4898 * used to build the request.
4899 *
4900 * If an error occurs, then queue the request on the board done
4901 * queue and return ASC_ERROR.
4902 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004903static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004905 /*
4906 * Mutually exclusive access is required to 'asc_scsi_q' and
4907 * 'asc_sg_head' until after the request is started.
4908 */
4909 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004911 /*
4912 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
4913 */
4914 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004916 /*
4917 * Build the ASC_SCSI_Q request.
4918 *
4919 * For narrow boards a CDB length maximum of 12 bytes
4920 * is supported.
4921 */
4922 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
Matthew Wilcoxecec1942007-07-30 08:08:22 -06004923 ASC_PRINT3("asc_build_req: board %d: cmd_len %d > "
4924 "ASC_MAX_CDB_LEN %d\n", boardp->id, scp->cmd_len,
4925 ASC_MAX_CDB_LEN);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004926 scp->result = HOST_BYTE(DID_ERROR);
4927 asc_enqueue(&boardp->done, scp, ASC_BACK);
4928 return ASC_ERROR;
4929 }
4930 asc_scsi_q.cdbptr = &scp->cmnd[0];
4931 asc_scsi_q.q2.cdb_len = scp->cmd_len;
4932 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
4933 asc_scsi_q.q1.target_lun = scp->device->lun;
4934 asc_scsi_q.q2.target_ix =
4935 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
4936 asc_scsi_q.q1.sense_addr =
4937 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4938 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004940 /*
4941 * If there are any outstanding requests for the current target,
4942 * then every 255th request send an ORDERED request. This heuristic
4943 * tries to retain the benefit of request sorting while preventing
4944 * request starvation. 255 is the max number of tags or pending commands
4945 * a device may have outstanding.
4946 *
4947 * The request count is incremented below for every successfully
4948 * started request.
4949 *
4950 */
4951 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
4952 (boardp->reqcnt[scp->device->id] % 255) == 0) {
4953 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
4954 } else {
4955 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
4956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004958 /*
4959 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
4960 * buffer command.
4961 */
4962 if (scp->use_sg == 0) {
4963 /*
4964 * CDB request of single contiguous buffer.
4965 */
4966 ASC_STATS(scp->device->host, cont_cnt);
4967 scp->SCp.dma_handle = scp->request_bufflen ?
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004968 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004969 scp->request_bufflen,
4970 scp->sc_data_direction) : 0;
4971 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
4972 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
4973 ASC_STATS_ADD(scp->device->host, cont_xfer,
4974 ASC_CEILING(scp->request_bufflen, 512));
4975 asc_scsi_q.q1.sg_queue_cnt = 0;
4976 asc_scsi_q.sg_head = NULL;
4977 } else {
4978 /*
4979 * CDB scatter-gather request list.
4980 */
4981 int sgcnt;
4982 int use_sg;
4983 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004985 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004986 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
4987 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004989 if (use_sg > scp->device->host->sg_tablesize) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04004990 ASC_PRINT3("asc_build_req: board %d: use_sg %d > "
4991 "sg_tablesize %d\n", boardp->id, use_sg,
4992 scp->device->host->sg_tablesize);
4993 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004994 scp->sc_data_direction);
4995 scp->result = HOST_BYTE(DID_ERROR);
4996 asc_enqueue(&boardp->done, scp, ASC_BACK);
4997 return ASC_ERROR;
4998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005000 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005002 /*
5003 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
5004 * structure to point to it.
5005 */
5006 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005008 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5009 asc_scsi_q.sg_head = &asc_sg_head;
5010 asc_scsi_q.q1.data_cnt = 0;
5011 asc_scsi_q.q1.data_addr = 0;
5012 /* This is a byte value, otherwise it would need to be swapped. */
5013 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5014 ASC_STATS_ADD(scp->device->host, sg_elem,
5015 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005017 /*
5018 * Convert scatter-gather list into ASC_SG_HEAD list.
5019 */
5020 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5021 asc_sg_head.sg_list[sgcnt].addr =
5022 cpu_to_le32(sg_dma_address(slp));
5023 asc_sg_head.sg_list[sgcnt].bytes =
5024 cpu_to_le32(sg_dma_len(slp));
5025 ASC_STATS_ADD(scp->device->host, sg_xfer,
5026 ASC_CEILING(sg_dma_len(slp), 512));
5027 }
5028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005030 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5031 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005033 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034}
5035
5036/*
5037 * Build a request structure for the Adv Library (Wide Board).
5038 *
5039 * If an adv_req_t can not be allocated to issue the request,
5040 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5041 *
5042 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5043 * microcode for DMA addresses or math operations are byte swapped
5044 * to little-endian order.
5045 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005046static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005048 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005050 adv_req_t *reqp;
5051 ADV_SCSI_REQ_Q *scsiqp;
5052 int i;
5053 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005055 /*
5056 * Allocate an adv_req_t structure from the board to execute
5057 * the command.
5058 */
5059 if (boardp->adv_reqp == NULL) {
5060 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5061 ASC_STATS(scp->device->host, adv_build_noreq);
5062 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005064 reqp = boardp->adv_reqp;
5065 boardp->adv_reqp = reqp->next_reqp;
5066 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005069 /*
5070 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5071 */
5072 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005074 /*
5075 * Initialize the structure.
5076 */
5077 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005079 /*
5080 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5081 */
5082 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005084 /*
5085 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5086 */
5087 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005089 /*
5090 * Build the ADV_SCSI_REQ_Q request.
5091 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005093 /*
5094 * Set CDB length and copy it to the request structure.
5095 * For wide boards a CDB length maximum of 16 bytes
5096 * is supported.
5097 */
5098 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5099 ASC_PRINT3
5100 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5101 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5102 scp->result = HOST_BYTE(DID_ERROR);
5103 asc_enqueue(&boardp->done, scp, ASC_BACK);
5104 return ASC_ERROR;
5105 }
5106 scsiqp->cdb_len = scp->cmd_len;
5107 /* Copy first 12 CDB bytes to cdb[]. */
5108 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5109 scsiqp->cdb[i] = scp->cmnd[i];
5110 }
5111 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5112 for (; i < scp->cmd_len; i++) {
5113 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005116 scsiqp->target_id = scp->device->id;
5117 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005119 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5120 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005122 /*
5123 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5124 * buffer command.
5125 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005127 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5128 scsiqp->vdata_addr = scp->request_buffer;
5129 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5130
5131 if (scp->use_sg == 0) {
5132 /*
5133 * CDB request of single contiguous buffer.
5134 */
5135 reqp->sgblkp = NULL;
5136 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5137 if (scp->request_bufflen) {
5138 scsiqp->vdata_addr = scp->request_buffer;
5139 scp->SCp.dma_handle =
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005140 dma_map_single(boardp->dev, scp->request_buffer,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005141 scp->request_bufflen,
5142 scp->sc_data_direction);
5143 } else {
5144 scsiqp->vdata_addr = NULL;
5145 scp->SCp.dma_handle = 0;
5146 }
5147 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5148 scsiqp->sg_list_ptr = NULL;
5149 scsiqp->sg_real_addr = 0;
5150 ASC_STATS(scp->device->host, cont_cnt);
5151 ASC_STATS_ADD(scp->device->host, cont_xfer,
5152 ASC_CEILING(scp->request_bufflen, 512));
5153 } else {
5154 /*
5155 * CDB scatter-gather request list.
5156 */
5157 struct scatterlist *slp;
5158 int use_sg;
5159
5160 slp = (struct scatterlist *)scp->request_buffer;
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005161 use_sg = dma_map_sg(boardp->dev, slp, scp->use_sg,
5162 scp->sc_data_direction);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005163
5164 if (use_sg > ADV_MAX_SG_LIST) {
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005165 ASC_PRINT3("adv_build_req: board %d: use_sg %d > "
5166 "ADV_MAX_SG_LIST %d\n", boardp->id, use_sg,
5167 scp->device->host->sg_tablesize);
5168 dma_unmap_sg(boardp->dev, slp, scp->use_sg,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005169 scp->sc_data_direction);
5170 scp->result = HOST_BYTE(DID_ERROR);
5171 asc_enqueue(&boardp->done, scp, ASC_BACK);
5172
5173 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005174 * Free the 'adv_req_t' structure by adding it back
5175 * to the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005176 */
5177 reqp->next_reqp = boardp->adv_reqp;
5178 boardp->adv_reqp = reqp;
5179
5180 return ASC_ERROR;
5181 }
5182
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005183 ret = adv_get_sglist(boardp, reqp, scp, use_sg);
5184 if (ret != ADV_SUCCESS) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005185 /*
Matthew Wilcox394dbf32007-07-26 11:56:40 -04005186 * Free the adv_req_t structure by adding it back to
5187 * the board free list.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005188 */
5189 reqp->next_reqp = boardp->adv_reqp;
5190 boardp->adv_reqp = reqp;
5191
5192 return ret;
5193 }
5194
5195 ASC_STATS(scp->device->host, sg_cnt);
5196 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5197 }
5198
5199 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5200 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5201
5202 *adv_scsiqpp = scsiqp;
5203
5204 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205}
5206
5207/*
5208 * Build scatter-gather list for Adv Library (Wide Board).
5209 *
5210 * Additional ADV_SG_BLOCK structures will need to be allocated
5211 * if the total number of scatter-gather elements exceeds
5212 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5213 * assumed to be physically contiguous.
5214 *
5215 * Return:
5216 * ADV_SUCCESS(1) - SG List successfully created
5217 * ADV_ERROR(-1) - SG List creation failed
5218 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005219static int
5220adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5221 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005223 adv_sgblk_t *sgblkp;
5224 ADV_SCSI_REQ_Q *scsiqp;
5225 struct scatterlist *slp;
5226 int sg_elem_cnt;
5227 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5228 ADV_PADDR sg_block_paddr;
5229 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005231 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5232 slp = (struct scatterlist *)scp->request_buffer;
5233 sg_elem_cnt = use_sg;
5234 prev_sg_block = NULL;
5235 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005237 do {
5238 /*
5239 * Allocate a 'adv_sgblk_t' structure from the board free
5240 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5241 * (15) scatter-gather elements.
5242 */
5243 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5244 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5245 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005247 /*
5248 * Allocation failed. Free 'adv_sgblk_t' structures already
5249 * allocated for the request.
5250 */
5251 while ((sgblkp = reqp->sgblkp) != NULL) {
5252 /* Remove 'sgblkp' from the request list. */
5253 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005255 /* Add 'sgblkp' to the board free list. */
5256 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5257 boardp->adv_sgblkp = sgblkp;
5258 }
5259 return ASC_BUSY;
5260 } else {
5261 /* Complete 'adv_sgblk_t' board allocation. */
5262 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5263 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005265 /*
5266 * Get 8 byte aligned virtual and physical addresses for
5267 * the allocated ADV_SG_BLOCK structure.
5268 */
5269 sg_block =
5270 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5271 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005273 /*
5274 * Check if this is the first 'adv_sgblk_t' for the request.
5275 */
5276 if (reqp->sgblkp == NULL) {
5277 /* Request's first scatter-gather block. */
5278 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005280 /*
5281 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5282 * address pointers.
5283 */
5284 scsiqp->sg_list_ptr = sg_block;
5285 scsiqp->sg_real_addr =
5286 cpu_to_le32(sg_block_paddr);
5287 } else {
5288 /* Request's second or later scatter-gather block. */
5289 sgblkp->next_sgblkp = reqp->sgblkp;
5290 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005292 /*
5293 * Point the previous ADV_SG_BLOCK structure to
5294 * the newly allocated ADV_SG_BLOCK structure.
5295 */
5296 ASC_ASSERT(prev_sg_block != NULL);
5297 prev_sg_block->sg_ptr =
5298 cpu_to_le32(sg_block_paddr);
5299 }
5300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005302 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5303 sg_block->sg_list[i].sg_addr =
5304 cpu_to_le32(sg_dma_address(slp));
5305 sg_block->sg_list[i].sg_count =
5306 cpu_to_le32(sg_dma_len(slp));
5307 ASC_STATS_ADD(scp->device->host, sg_xfer,
5308 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005310 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5311 sg_block->sg_cnt = i + 1;
5312 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5313 return ADV_SUCCESS;
5314 }
5315 slp++;
5316 }
5317 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5318 prev_sg_block = sg_block;
5319 }
5320 while (1);
5321 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322}
5323
5324/*
5325 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5326 *
5327 * Interrupt callback function for the Narrow SCSI Asc Library.
5328 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005329static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005331 asc_board_t *boardp;
5332 struct scsi_cmnd *scp;
5333 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005335 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5336 (ulong)asc_dvc_varp, (ulong)qdonep);
5337 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005339 /*
5340 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5341 * command that has been completed.
5342 */
5343 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5344 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005346 if (scp == NULL) {
5347 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5348 return;
5349 }
5350 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005352 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005353 ASC_STATS(shost, callback);
5354 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005356 /*
5357 * If the request isn't found on the active queue, it may
5358 * have been removed to handle a reset request.
5359 * Display a message and return.
5360 */
5361 boardp = ASC_BOARDP(shost);
5362 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5363 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5364 ASC_PRINT2
5365 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5366 boardp->id, (ulong)scp);
5367 return;
5368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005370 /*
5371 * 'qdonep' contains the command's ending status.
5372 */
5373 switch (qdonep->d3.done_stat) {
5374 case QD_NO_ERROR:
5375 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5376 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005378 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005379 * Check for an underrun condition.
5380 *
5381 * If there was no error and an underrun condition, then
Matthew Wilcox47d853c2007-07-26 11:41:33 -04005382 * return the number of underrun bytes.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005383 */
5384 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5385 qdonep->remain_bytes <= scp->request_bufflen) {
5386 ASC_DBG1(1,
5387 "asc_isr_callback: underrun condition %u bytes\n",
5388 (unsigned)qdonep->remain_bytes);
5389 scp->resid = qdonep->remain_bytes;
5390 }
5391 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005393 case QD_WITH_ERROR:
5394 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5395 switch (qdonep->d3.host_stat) {
5396 case QHSTA_NO_ERROR:
5397 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5398 ASC_DBG(2,
5399 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5400 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5401 sizeof(scp->sense_buffer));
5402 /*
5403 * Note: The 'status_byte()' macro used by target drivers
5404 * defined in scsi.h shifts the status byte returned by
5405 * host drivers right by 1 bit. This is why target drivers
5406 * also use right shifted status byte definitions. For
5407 * instance target drivers use CHECK_CONDITION, defined to
5408 * 0x1, instead of the SCSI defined check condition value
5409 * of 0x2. Host drivers are supposed to return the status
5410 * byte as it is defined by SCSI.
5411 */
5412 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5413 STATUS_BYTE(qdonep->d3.scsi_stat);
5414 } else {
5415 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5416 }
5417 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005419 default:
5420 /* QHSTA error occurred */
5421 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5422 qdonep->d3.host_stat);
5423 scp->result = HOST_BYTE(DID_BAD_TARGET);
5424 break;
5425 }
5426 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005428 case QD_ABORTED_BY_HOST:
5429 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5430 scp->result =
5431 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5432 scsi_msg) |
5433 STATUS_BYTE(qdonep->d3.scsi_stat);
5434 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005436 default:
5437 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5438 qdonep->d3.done_stat);
5439 scp->result =
5440 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5441 scsi_msg) |
5442 STATUS_BYTE(qdonep->d3.scsi_stat);
5443 break;
5444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005446 /*
5447 * If the 'init_tidmask' bit isn't already set for the target and the
5448 * current request finished normally, then set the bit for the target
5449 * to indicate that a device is present.
5450 */
5451 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5452 qdonep->d3.done_stat == QD_NO_ERROR &&
5453 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5454 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005457 /*
5458 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5459 * function, add the command to the end of the board's done queue.
5460 * The done function for the command will be called from
5461 * advansys_interrupt().
5462 */
5463 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005465 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466}
5467
5468/*
5469 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5470 *
5471 * Callback function for the Wide SCSI Adv Library.
5472 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005473static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005474{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005475 asc_board_t *boardp;
5476 adv_req_t *reqp;
5477 adv_sgblk_t *sgblkp;
5478 struct scsi_cmnd *scp;
5479 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005480 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005482 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5483 (ulong)adv_dvc_varp, (ulong)scsiqp);
5484 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005486 /*
5487 * Get the adv_req_t structure for the command that has been
5488 * completed. The adv_req_t structure actually contains the
5489 * completed ADV_SCSI_REQ_Q structure.
5490 */
5491 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5492 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5493 if (reqp == NULL) {
5494 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5495 return;
5496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005498 /*
5499 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5500 * command that has been completed.
5501 *
5502 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5503 * if any, are dropped, because a board structure pointer can not be
5504 * determined.
5505 */
5506 scp = reqp->cmndp;
5507 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5508 if (scp == NULL) {
5509 ASC_PRINT
5510 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5511 return;
5512 }
5513 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005515 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005516 ASC_STATS(shost, callback);
5517 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005519 /*
5520 * If the request isn't found on the active queue, it may have been
5521 * removed to handle a reset request. Display a message and return.
5522 *
5523 * Note: Because the structure may still be in use don't attempt
5524 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5525 */
5526 boardp = ASC_BOARDP(shost);
5527 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5528 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5529 ASC_PRINT2
5530 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5531 boardp->id, (ulong)scp);
5532 return;
5533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005535 /*
5536 * 'done_status' contains the command's ending status.
5537 */
5538 switch (scsiqp->done_status) {
5539 case QD_NO_ERROR:
5540 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5541 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005543 /*
5544 * Check for an underrun condition.
5545 *
5546 * If there was no error and an underrun condition, then
5547 * then return the number of underrun bytes.
5548 */
5549 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5550 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5551 resid_cnt <= scp->request_bufflen) {
5552 ASC_DBG1(1,
5553 "adv_isr_callback: underrun condition %lu bytes\n",
5554 (ulong)resid_cnt);
5555 scp->resid = resid_cnt;
5556 }
5557 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005559 case QD_WITH_ERROR:
5560 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5561 switch (scsiqp->host_status) {
5562 case QHSTA_NO_ERROR:
5563 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5564 ASC_DBG(2,
5565 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5566 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5567 sizeof(scp->sense_buffer));
5568 /*
5569 * Note: The 'status_byte()' macro used by target drivers
5570 * defined in scsi.h shifts the status byte returned by
5571 * host drivers right by 1 bit. This is why target drivers
5572 * also use right shifted status byte definitions. For
5573 * instance target drivers use CHECK_CONDITION, defined to
5574 * 0x1, instead of the SCSI defined check condition value
5575 * of 0x2. Host drivers are supposed to return the status
5576 * byte as it is defined by SCSI.
5577 */
5578 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5579 STATUS_BYTE(scsiqp->scsi_status);
5580 } else {
5581 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5582 }
5583 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005585 default:
5586 /* Some other QHSTA error occurred. */
5587 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5588 scsiqp->host_status);
5589 scp->result = HOST_BYTE(DID_BAD_TARGET);
5590 break;
5591 }
5592 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005594 case QD_ABORTED_BY_HOST:
5595 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5596 scp->result =
5597 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5598 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005600 default:
5601 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5602 scsiqp->done_status);
5603 scp->result =
5604 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5605 break;
5606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005608 /*
5609 * If the 'init_tidmask' bit isn't already set for the target and the
5610 * current request finished normally, then set the bit for the target
5611 * to indicate that a device is present.
5612 */
5613 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5614 scsiqp->done_status == QD_NO_ERROR &&
5615 scsiqp->host_status == QHSTA_NO_ERROR) {
5616 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005619 /*
5620 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5621 * function, add the command to the end of the board's done queue.
5622 * The done function for the command will be called from
5623 * advansys_interrupt().
5624 */
5625 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005627 /*
5628 * Free all 'adv_sgblk_t' structures allocated for the request.
5629 */
5630 while ((sgblkp = reqp->sgblkp) != NULL) {
5631 /* Remove 'sgblkp' from the request list. */
5632 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005634 /* Add 'sgblkp' to the board free list. */
5635 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5636 boardp->adv_sgblkp = sgblkp;
5637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005639 /*
5640 * Free the adv_req_t structure used with the command by adding
5641 * it back to the board free list.
5642 */
5643 reqp->next_reqp = boardp->adv_reqp;
5644 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005646 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005648 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649}
5650
5651/*
5652 * adv_async_callback() - Adv Library asynchronous event callback function.
5653 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005654static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005656 switch (code) {
5657 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5658 /*
5659 * The firmware detected a SCSI Bus reset.
5660 */
5661 ASC_DBG(0,
5662 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5663 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005665 case ADV_ASYNC_RDMA_FAILURE:
5666 /*
5667 * Handle RDMA failure by resetting the SCSI Bus and
5668 * possibly the chip if it is unresponsive. Log the error
5669 * with a unique code.
5670 */
5671 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5672 AdvResetChipAndSB(adv_dvc_varp);
5673 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005675 case ADV_HOST_SCSI_BUS_RESET:
5676 /*
5677 * Host generated SCSI bus reset occurred.
5678 */
5679 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5680 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005682 default:
5683 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5684 break;
5685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686}
5687
5688/*
5689 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5690 * to indicate a command is queued for the device.
5691 *
5692 * 'flag' may be either ASC_FRONT or ASC_BACK.
5693 *
5694 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5695 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005696static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005698 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005700 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5701 (ulong)ascq, (ulong)reqp, flag);
5702 ASC_ASSERT(reqp != NULL);
5703 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5704 tid = REQPTID(reqp);
5705 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5706 if (flag == ASC_FRONT) {
5707 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5708 ascq->q_first[tid] = reqp;
5709 /* If the queue was empty, set the last pointer. */
5710 if (ascq->q_last[tid] == NULL) {
5711 ascq->q_last[tid] = reqp;
5712 }
5713 } else { /* ASC_BACK */
5714 if (ascq->q_last[tid] != NULL) {
5715 ascq->q_last[tid]->host_scribble =
5716 (unsigned char *)reqp;
5717 }
5718 ascq->q_last[tid] = reqp;
5719 reqp->host_scribble = NULL;
5720 /* If the queue was empty, set the first pointer. */
5721 if (ascq->q_first[tid] == NULL) {
5722 ascq->q_first[tid] = reqp;
5723 }
5724 }
5725 /* The queue has at least one entry, set its bit. */
5726 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005728 /* Maintain request queue statistics. */
5729 ascq->q_tot_cnt[tid]++;
5730 ascq->q_cur_cnt[tid]++;
5731 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5732 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5733 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5734 tid, ascq->q_max_cnt[tid]);
5735 }
5736 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005738 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5739 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740}
5741
5742/*
5743 * Return first queued 'REQP' on the specified queue for
5744 * the specified target device. Clear the 'tidmask' bit for
5745 * the device if no more commands are left queued for it.
5746 *
5747 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5748 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005749static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005751 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005753 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5754 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5755 if ((reqp = ascq->q_first[tid]) != NULL) {
5756 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5757 ascq->q_first[tid] = REQPNEXT(reqp);
5758 /* If the queue is empty, clear its bit and the last pointer. */
5759 if (ascq->q_first[tid] == NULL) {
5760 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5761 ASC_ASSERT(ascq->q_last[tid] == reqp);
5762 ascq->q_last[tid] = NULL;
5763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005765 /* Maintain request queue statistics. */
5766 ascq->q_cur_cnt[tid]--;
5767 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
5768 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005770 }
5771 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
5772 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773}
5774
5775/*
5776 * Return a pointer to a singly linked list of all the requests queued
5777 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
5778 *
5779 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
5780 * the last request returned in the singly linked list.
5781 *
5782 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
5783 * then all queued requests are concatenated into one list and
5784 * returned.
5785 *
5786 * Note: If 'lastpp' is used to append a new list to the end of
5787 * an old list, only change the old list last pointer if '*lastpp'
5788 * (or the function return value) is not NULL, i.e. use a temporary
5789 * variable for 'lastpp' and check its value after the function return
5790 * before assigning it to the list last pointer.
5791 *
5792 * Unfortunately collecting queuing time statistics adds overhead to
5793 * the function that isn't inherent to the function's algorithm.
5794 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005795static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005797 REQP firstp, lastp;
5798 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005800 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5801 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005803 /*
5804 * If 'tid' is not ASC_TID_ALL, return requests only for
5805 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
5806 * requests for all tids.
5807 */
5808 if (tid != ASC_TID_ALL) {
5809 /* Return all requests for the specified 'tid'. */
5810 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
5811 /* List is empty; Set first and last return pointers to NULL. */
5812 firstp = lastp = NULL;
5813 } else {
5814 firstp = ascq->q_first[tid];
5815 lastp = ascq->q_last[tid];
5816 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
5817 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005819 {
5820 REQP reqp;
5821 ascq->q_cur_cnt[tid] = 0;
5822 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5823 REQTIMESTAT("asc_dequeue_list", ascq,
5824 reqp, tid);
5825 }
5826 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005827#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005828 }
5829 } else {
5830 /* Return all requests for all tids. */
5831 firstp = lastp = NULL;
5832 for (i = 0; i <= ADV_MAX_TID; i++) {
5833 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
5834 if (firstp == NULL) {
5835 firstp = ascq->q_first[i];
5836 lastp = ascq->q_last[i];
5837 } else {
5838 ASC_ASSERT(lastp != NULL);
5839 lastp->host_scribble =
5840 (unsigned char *)ascq->q_first[i];
5841 lastp = ascq->q_last[i];
5842 }
5843 ascq->q_first[i] = ascq->q_last[i] = NULL;
5844 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005845#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005846 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005848 }
5849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005850#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005851 {
5852 REQP reqp;
5853 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5854 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
5855 reqp->device->id);
5856 }
5857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005859 }
5860 if (lastpp) {
5861 *lastpp = lastp;
5862 }
5863 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
5864 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865}
5866
5867/*
5868 * Remove the specified 'REQP' from the specified queue for
5869 * the specified target device. Clear the 'tidmask' bit for the
5870 * device if no more commands are left queued for it.
5871 *
5872 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
5873 *
5874 * Return ASC_TRUE if the command was found and removed,
5875 * otherwise return ASC_FALSE.
5876 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005877static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005879 REQP currp, prevp;
5880 int tid;
5881 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005883 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
5884 (ulong)ascq, (ulong)reqp);
5885 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005887 tid = REQPTID(reqp);
5888 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005890 /*
5891 * Handle the common case of 'reqp' being the first
5892 * entry on the queue.
5893 */
5894 if (reqp == ascq->q_first[tid]) {
5895 ret = ASC_TRUE;
5896 ascq->q_first[tid] = REQPNEXT(reqp);
5897 /* If the queue is now empty, clear its bit and the last pointer. */
5898 if (ascq->q_first[tid] == NULL) {
5899 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5900 ASC_ASSERT(ascq->q_last[tid] == reqp);
5901 ascq->q_last[tid] = NULL;
5902 }
5903 } else if (ascq->q_first[tid] != NULL) {
5904 ASC_ASSERT(ascq->q_last[tid] != NULL);
5905 /*
5906 * Because the case of 'reqp' being the first entry has been
5907 * handled above and it is known the queue is not empty, if
5908 * 'reqp' is found on the queue it is guaranteed the queue will
5909 * not become empty and that 'q_first[tid]' will not be changed.
5910 *
5911 * Set 'prevp' to the first entry, 'currp' to the second entry,
5912 * and search for 'reqp'.
5913 */
5914 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
5915 currp; prevp = currp, currp = REQPNEXT(currp)) {
5916 if (currp == reqp) {
5917 ret = ASC_TRUE;
5918 prevp->host_scribble =
5919 (unsigned char *)REQPNEXT(currp);
5920 reqp->host_scribble = NULL;
5921 if (ascq->q_last[tid] == reqp) {
5922 ascq->q_last[tid] = prevp;
5923 }
5924 break;
5925 }
5926 }
5927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005929 /* Maintain request queue statistics. */
5930 if (ret == ASC_TRUE) {
5931 ascq->q_cur_cnt[tid]--;
5932 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
5933 }
5934 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005936 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
5937 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938}
5939
5940/*
5941 * Execute as many queued requests as possible for the specified queue.
5942 *
5943 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
5944 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005945static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005947 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
5948 REQP reqp;
5949 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005951 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
5952 /*
5953 * Execute queued commands for devices attached to
5954 * the current board in round-robin fashion.
5955 */
5956 scan_tidmask = ascq->q_tidmask;
5957 do {
5958 for (i = 0; i <= ADV_MAX_TID; i++) {
5959 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
5960 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
5961 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
5962 } else
5963 if (asc_execute_scsi_cmnd
5964 ((struct scsi_cmnd *)reqp)
5965 == ASC_BUSY) {
5966 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
5967 /*
5968 * The request returned ASC_BUSY. Enqueue at the front of
5969 * target's waiting list to maintain correct ordering.
5970 */
5971 asc_enqueue(ascq, reqp, ASC_FRONT);
5972 }
5973 }
5974 }
5975 } while (scan_tidmask);
5976 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977}
5978
5979#ifdef CONFIG_PROC_FS
5980/*
5981 * asc_prt_board_devices()
5982 *
5983 * Print driver information for devices attached to the board.
5984 *
5985 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
5986 * cf. asc_prt_line().
5987 *
5988 * Return the number of characters copied into 'cp'. No more than
5989 * 'cplen' characters will be copied to 'cp'.
5990 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005991static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005993 asc_board_t *boardp;
5994 int leftlen;
5995 int totlen;
5996 int len;
5997 int chip_scsi_id;
5998 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006000 boardp = ASC_BOARDP(shost);
6001 leftlen = cplen;
6002 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006004 len = asc_prt_line(cp, leftlen,
6005 "\nDevice Information for AdvanSys SCSI Host %d:\n",
6006 shost->host_no);
6007 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006009 if (ASC_NARROW_BOARD(boardp)) {
6010 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6011 } else {
6012 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6013 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006015 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6016 ASC_PRT_NEXT();
6017 for (i = 0; i <= ADV_MAX_TID; i++) {
6018 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6019 len = asc_prt_line(cp, leftlen, " %X,", i);
6020 ASC_PRT_NEXT();
6021 }
6022 }
6023 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6024 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006026 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027}
6028
6029/*
6030 * Display Wide Board BIOS Information.
6031 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006032static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006034 asc_board_t *boardp;
6035 int leftlen;
6036 int totlen;
6037 int len;
6038 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006040 boardp = ASC_BOARDP(shost);
6041 leftlen = cplen;
6042 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006043
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006044 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6045 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006047 /*
6048 * If the BIOS saved a valid signature, then fill in
6049 * the BIOS code segment base address.
6050 */
6051 if (boardp->bios_signature != 0x55AA) {
6052 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6053 ASC_PRT_NEXT();
6054 len = asc_prt_line(cp, leftlen,
6055 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6056 ASC_PRT_NEXT();
6057 len = asc_prt_line(cp, leftlen,
6058 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6059 ASC_PRT_NEXT();
6060 } else {
6061 major = (boardp->bios_version >> 12) & 0xF;
6062 minor = (boardp->bios_version >> 8) & 0xF;
6063 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006065 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6066 major, minor,
6067 letter >= 26 ? '?' : letter + 'A');
6068 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006070 /*
6071 * Current available ROM BIOS release is 3.1I for UW
6072 * and 3.2I for U2W. This code doesn't differentiate
6073 * UW and U2W boards.
6074 */
6075 if (major < 3 || (major <= 3 && minor < 1) ||
6076 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6077 len = asc_prt_line(cp, leftlen,
6078 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6079 ASC_PRT_NEXT();
6080 len = asc_prt_line(cp, leftlen,
6081 "ftp://ftp.connectcom.net/pub\n");
6082 ASC_PRT_NEXT();
6083 }
6084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006086 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087}
6088
6089/*
6090 * Add serial number to information bar if signature AAh
6091 * is found in at bit 15-9 (7 bits) of word 1.
6092 *
6093 * Serial Number consists fo 12 alpha-numeric digits.
6094 *
6095 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6096 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6097 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6098 * 5 - Product revision (A-J) Word0: " "
6099 *
6100 * Signature Word1: 15-9 (7 bits)
6101 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6102 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6103 *
6104 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6105 *
6106 * Note 1: Only production cards will have a serial number.
6107 *
6108 * Note 2: Signature is most significant 7 bits (0xFE).
6109 *
6110 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6111 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006112static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006114 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006116 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6117 return ASC_FALSE;
6118 } else {
6119 /*
6120 * First word - 6 digits.
6121 */
6122 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006124 /* Product type - 1st digit. */
6125 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6126 /* Product type is P=Prototype */
6127 *cp += 0x8;
6128 }
6129 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006131 /* Manufacturing location - 2nd digit. */
6132 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006134 /* Product ID - 3rd, 4th digits. */
6135 num = w & 0x3FF;
6136 *cp++ = '0' + (num / 100);
6137 num %= 100;
6138 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006139
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006140 /* Product revision - 5th digit. */
6141 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006142
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006143 /*
6144 * Second word
6145 */
6146 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006148 /*
6149 * Year - 6th digit.
6150 *
6151 * If bit 15 of third word is set, then the
6152 * last digit of the year is greater than 7.
6153 */
6154 if (serialnum[2] & 0x8000) {
6155 *cp++ = '8' + ((w & 0x1C0) >> 6);
6156 } else {
6157 *cp++ = '0' + ((w & 0x1C0) >> 6);
6158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006160 /* Week of year - 7th, 8th digits. */
6161 num = w & 0x003F;
6162 *cp++ = '0' + num / 10;
6163 num %= 10;
6164 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006166 /*
6167 * Third word
6168 */
6169 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006170
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006171 /* Serial number - 9th digit. */
6172 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006173
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006174 /* 10th, 11th, 12th digits. */
6175 num = w % 1000;
6176 *cp++ = '0' + num / 100;
6177 num %= 100;
6178 *cp++ = '0' + num / 10;
6179 num %= 10;
6180 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006181
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006182 *cp = '\0'; /* Null Terminate the string. */
6183 return ASC_TRUE;
6184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185}
6186
6187/*
6188 * asc_prt_asc_board_eeprom()
6189 *
6190 * Print board EEPROM configuration.
6191 *
6192 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6193 * cf. asc_prt_line().
6194 *
6195 * Return the number of characters copied into 'cp'. No more than
6196 * 'cplen' characters will be copied to 'cp'.
6197 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006198static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006200 asc_board_t *boardp;
6201 ASC_DVC_VAR *asc_dvc_varp;
6202 int leftlen;
6203 int totlen;
6204 int len;
6205 ASCEEP_CONFIG *ep;
6206 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006208 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006210 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006212 boardp = ASC_BOARDP(shost);
6213 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6214 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006216 leftlen = cplen;
6217 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006219 len = asc_prt_line(cp, leftlen,
6220 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6221 shost->host_no);
6222 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006224 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6225 == ASC_TRUE) {
6226 len =
6227 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6228 serialstr);
6229 ASC_PRT_NEXT();
6230 } else {
6231 if (ep->adapter_info[5] == 0xBB) {
6232 len = asc_prt_line(cp, leftlen,
6233 " Default Settings Used for EEPROM-less Adapter.\n");
6234 ASC_PRT_NEXT();
6235 } else {
6236 len = asc_prt_line(cp, leftlen,
6237 " Serial Number Signature Not Present.\n");
6238 ASC_PRT_NEXT();
6239 }
6240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006242 len = asc_prt_line(cp, leftlen,
6243 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6244 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6245 ep->max_tag_qng);
6246 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006247
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006248 len = asc_prt_line(cp, leftlen,
6249 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6250 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006252 len = asc_prt_line(cp, leftlen, " Target ID: ");
6253 ASC_PRT_NEXT();
6254 for (i = 0; i <= ASC_MAX_TID; i++) {
6255 len = asc_prt_line(cp, leftlen, " %d", i);
6256 ASC_PRT_NEXT();
6257 }
6258 len = asc_prt_line(cp, leftlen, "\n");
6259 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006261 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6262 ASC_PRT_NEXT();
6263 for (i = 0; i <= ASC_MAX_TID; i++) {
6264 len = asc_prt_line(cp, leftlen, " %c",
6265 (ep->
6266 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6267 'N');
6268 ASC_PRT_NEXT();
6269 }
6270 len = asc_prt_line(cp, leftlen, "\n");
6271 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006273 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6274 ASC_PRT_NEXT();
6275 for (i = 0; i <= ASC_MAX_TID; i++) {
6276 len = asc_prt_line(cp, leftlen, " %c",
6277 (ep->
6278 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6279 'N');
6280 ASC_PRT_NEXT();
6281 }
6282 len = asc_prt_line(cp, leftlen, "\n");
6283 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006285 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6286 ASC_PRT_NEXT();
6287 for (i = 0; i <= ASC_MAX_TID; i++) {
6288 len = asc_prt_line(cp, leftlen, " %c",
6289 (ep->
6290 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6291 'N');
6292 ASC_PRT_NEXT();
6293 }
6294 len = asc_prt_line(cp, leftlen, "\n");
6295 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006297 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6298 ASC_PRT_NEXT();
6299 for (i = 0; i <= ASC_MAX_TID; i++) {
6300 len = asc_prt_line(cp, leftlen, " %c",
6301 (ep->
6302 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6303 'N');
6304 ASC_PRT_NEXT();
6305 }
6306 len = asc_prt_line(cp, leftlen, "\n");
6307 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308
6309#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006310 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6311 len = asc_prt_line(cp, leftlen,
6312 " Host ISA DMA speed: %d MB/S\n",
6313 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6314 ASC_PRT_NEXT();
6315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316#endif /* CONFIG_ISA */
6317
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006318 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006319}
6320
6321/*
6322 * asc_prt_adv_board_eeprom()
6323 *
6324 * Print board EEPROM configuration.
6325 *
6326 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6327 * cf. asc_prt_line().
6328 *
6329 * Return the number of characters copied into 'cp'. No more than
6330 * 'cplen' characters will be copied to 'cp'.
6331 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006332static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006334 asc_board_t *boardp;
6335 ADV_DVC_VAR *adv_dvc_varp;
6336 int leftlen;
6337 int totlen;
6338 int len;
6339 int i;
6340 char *termstr;
6341 uchar serialstr[13];
6342 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6343 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6344 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6345 ushort word;
6346 ushort *wordp;
6347 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006349 boardp = ASC_BOARDP(shost);
6350 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6351 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6352 ep_3550 = &boardp->eep_config.adv_3550_eep;
6353 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6354 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6355 } else {
6356 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006359 leftlen = cplen;
6360 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006361
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006362 len = asc_prt_line(cp, leftlen,
6363 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6364 shost->host_no);
6365 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006366
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006367 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6368 wordp = &ep_3550->serial_number_word1;
6369 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6370 wordp = &ep_38C0800->serial_number_word1;
6371 } else {
6372 wordp = &ep_38C1600->serial_number_word1;
6373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006375 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6376 len =
6377 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6378 serialstr);
6379 ASC_PRT_NEXT();
6380 } else {
6381 len = asc_prt_line(cp, leftlen,
6382 " Serial Number Signature Not Present.\n");
6383 ASC_PRT_NEXT();
6384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006386 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6387 len = asc_prt_line(cp, leftlen,
6388 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6389 ep_3550->adapter_scsi_id,
6390 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6391 ASC_PRT_NEXT();
6392 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6393 len = asc_prt_line(cp, leftlen,
6394 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6395 ep_38C0800->adapter_scsi_id,
6396 ep_38C0800->max_host_qng,
6397 ep_38C0800->max_dvc_qng);
6398 ASC_PRT_NEXT();
6399 } else {
6400 len = asc_prt_line(cp, leftlen,
6401 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6402 ep_38C1600->adapter_scsi_id,
6403 ep_38C1600->max_host_qng,
6404 ep_38C1600->max_dvc_qng);
6405 ASC_PRT_NEXT();
6406 }
6407 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6408 word = ep_3550->termination;
6409 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6410 word = ep_38C0800->termination_lvd;
6411 } else {
6412 word = ep_38C1600->termination_lvd;
6413 }
6414 switch (word) {
6415 case 1:
6416 termstr = "Low Off/High Off";
6417 break;
6418 case 2:
6419 termstr = "Low Off/High On";
6420 break;
6421 case 3:
6422 termstr = "Low On/High On";
6423 break;
6424 default:
6425 case 0:
6426 termstr = "Automatic";
6427 break;
6428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006429
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006430 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6431 len = asc_prt_line(cp, leftlen,
6432 " termination: %u (%s), bios_ctrl: 0x%x\n",
6433 ep_3550->termination, termstr,
6434 ep_3550->bios_ctrl);
6435 ASC_PRT_NEXT();
6436 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6437 len = asc_prt_line(cp, leftlen,
6438 " termination: %u (%s), bios_ctrl: 0x%x\n",
6439 ep_38C0800->termination_lvd, termstr,
6440 ep_38C0800->bios_ctrl);
6441 ASC_PRT_NEXT();
6442 } else {
6443 len = asc_prt_line(cp, leftlen,
6444 " termination: %u (%s), bios_ctrl: 0x%x\n",
6445 ep_38C1600->termination_lvd, termstr,
6446 ep_38C1600->bios_ctrl);
6447 ASC_PRT_NEXT();
6448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006450 len = asc_prt_line(cp, leftlen, " Target ID: ");
6451 ASC_PRT_NEXT();
6452 for (i = 0; i <= ADV_MAX_TID; i++) {
6453 len = asc_prt_line(cp, leftlen, " %X", i);
6454 ASC_PRT_NEXT();
6455 }
6456 len = asc_prt_line(cp, leftlen, "\n");
6457 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006458
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006459 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6460 word = ep_3550->disc_enable;
6461 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6462 word = ep_38C0800->disc_enable;
6463 } else {
6464 word = ep_38C1600->disc_enable;
6465 }
6466 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6467 ASC_PRT_NEXT();
6468 for (i = 0; i <= ADV_MAX_TID; i++) {
6469 len = asc_prt_line(cp, leftlen, " %c",
6470 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6471 ASC_PRT_NEXT();
6472 }
6473 len = asc_prt_line(cp, leftlen, "\n");
6474 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006475
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006476 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6477 word = ep_3550->tagqng_able;
6478 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6479 word = ep_38C0800->tagqng_able;
6480 } else {
6481 word = ep_38C1600->tagqng_able;
6482 }
6483 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6484 ASC_PRT_NEXT();
6485 for (i = 0; i <= ADV_MAX_TID; i++) {
6486 len = asc_prt_line(cp, leftlen, " %c",
6487 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6488 ASC_PRT_NEXT();
6489 }
6490 len = asc_prt_line(cp, leftlen, "\n");
6491 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006492
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006493 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6494 word = ep_3550->start_motor;
6495 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6496 word = ep_38C0800->start_motor;
6497 } else {
6498 word = ep_38C1600->start_motor;
6499 }
6500 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6501 ASC_PRT_NEXT();
6502 for (i = 0; i <= ADV_MAX_TID; i++) {
6503 len = asc_prt_line(cp, leftlen, " %c",
6504 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6505 ASC_PRT_NEXT();
6506 }
6507 len = asc_prt_line(cp, leftlen, "\n");
6508 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006509
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006510 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6511 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6512 ASC_PRT_NEXT();
6513 for (i = 0; i <= ADV_MAX_TID; i++) {
6514 len = asc_prt_line(cp, leftlen, " %c",
6515 (ep_3550->
6516 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6517 'Y' : 'N');
6518 ASC_PRT_NEXT();
6519 }
6520 len = asc_prt_line(cp, leftlen, "\n");
6521 ASC_PRT_NEXT();
6522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006523
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006524 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6525 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6526 ASC_PRT_NEXT();
6527 for (i = 0; i <= ADV_MAX_TID; i++) {
6528 len = asc_prt_line(cp, leftlen, " %c",
6529 (ep_3550->
6530 ultra_able & ADV_TID_TO_TIDMASK(i))
6531 ? 'Y' : 'N');
6532 ASC_PRT_NEXT();
6533 }
6534 len = asc_prt_line(cp, leftlen, "\n");
6535 ASC_PRT_NEXT();
6536 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006537
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006538 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6539 word = ep_3550->wdtr_able;
6540 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6541 word = ep_38C0800->wdtr_able;
6542 } else {
6543 word = ep_38C1600->wdtr_able;
6544 }
6545 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6546 ASC_PRT_NEXT();
6547 for (i = 0; i <= ADV_MAX_TID; i++) {
6548 len = asc_prt_line(cp, leftlen, " %c",
6549 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6550 ASC_PRT_NEXT();
6551 }
6552 len = asc_prt_line(cp, leftlen, "\n");
6553 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006555 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6556 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6557 len = asc_prt_line(cp, leftlen,
6558 " Synchronous Transfer Speed (Mhz):\n ");
6559 ASC_PRT_NEXT();
6560 for (i = 0; i <= ADV_MAX_TID; i++) {
6561 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006562
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006563 if (i == 0) {
6564 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6565 } else if (i == 4) {
6566 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6567 } else if (i == 8) {
6568 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6569 } else if (i == 12) {
6570 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6571 }
6572 switch (sdtr_speed & ADV_MAX_TID) {
6573 case 0:
6574 speed_str = "Off";
6575 break;
6576 case 1:
6577 speed_str = " 5";
6578 break;
6579 case 2:
6580 speed_str = " 10";
6581 break;
6582 case 3:
6583 speed_str = " 20";
6584 break;
6585 case 4:
6586 speed_str = " 40";
6587 break;
6588 case 5:
6589 speed_str = " 80";
6590 break;
6591 default:
6592 speed_str = "Unk";
6593 break;
6594 }
6595 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6596 ASC_PRT_NEXT();
6597 if (i == 7) {
6598 len = asc_prt_line(cp, leftlen, "\n ");
6599 ASC_PRT_NEXT();
6600 }
6601 sdtr_speed >>= 4;
6602 }
6603 len = asc_prt_line(cp, leftlen, "\n");
6604 ASC_PRT_NEXT();
6605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006606
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006607 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006608}
6609
6610/*
6611 * asc_prt_driver_conf()
6612 *
6613 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6614 * cf. asc_prt_line().
6615 *
6616 * Return the number of characters copied into 'cp'. No more than
6617 * 'cplen' characters will be copied to 'cp'.
6618 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006619static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006620{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006621 asc_board_t *boardp;
6622 int leftlen;
6623 int totlen;
6624 int len;
6625 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006627 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006628
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006629 leftlen = cplen;
6630 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006631
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006632 len = asc_prt_line(cp, leftlen,
6633 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6634 shost->host_no);
6635 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006636
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006637 len = asc_prt_line(cp, leftlen,
6638 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6639 shost->host_busy, shost->last_reset, shost->max_id,
6640 shost->max_lun, shost->max_channel);
6641 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006643 len = asc_prt_line(cp, leftlen,
6644 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6645 shost->unique_id, shost->can_queue, shost->this_id,
6646 shost->sg_tablesize, shost->cmd_per_lun);
6647 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006648
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006649 len = asc_prt_line(cp, leftlen,
6650 " unchecked_isa_dma %d, use_clustering %d\n",
6651 shost->unchecked_isa_dma, shost->use_clustering);
6652 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006653
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006654 len = asc_prt_line(cp, leftlen,
6655 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6656 boardp->flags, boardp->last_reset, jiffies,
6657 boardp->asc_n_io_port);
6658 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006659
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04006660 len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006661 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006662
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006663 if (ASC_NARROW_BOARD(boardp)) {
6664 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6665 } else {
6666 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006668
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006669 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006670}
6671
6672/*
6673 * asc_prt_asc_board_info()
6674 *
6675 * Print dynamic board configuration information.
6676 *
6677 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6678 * cf. asc_prt_line().
6679 *
6680 * Return the number of characters copied into 'cp'. No more than
6681 * 'cplen' characters will be copied to 'cp'.
6682 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006683static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006684{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006685 asc_board_t *boardp;
6686 int chip_scsi_id;
6687 int leftlen;
6688 int totlen;
6689 int len;
6690 ASC_DVC_VAR *v;
6691 ASC_DVC_CFG *c;
6692 int i;
6693 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006694
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006695 boardp = ASC_BOARDP(shost);
6696 v = &boardp->dvc_var.asc_dvc_var;
6697 c = &boardp->dvc_cfg.asc_dvc_cfg;
6698 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006699
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006700 leftlen = cplen;
6701 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006702
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006703 len = asc_prt_line(cp, leftlen,
6704 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6705 shost->host_no);
6706 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006708 len = asc_prt_line(cp, leftlen,
6709 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6710 c->chip_version, c->lib_version, c->lib_serial_no,
6711 c->mcode_date);
6712 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006714 len = asc_prt_line(cp, leftlen,
6715 " mcode_version 0x%x, err_code %u\n",
6716 c->mcode_version, v->err_code);
6717 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006718
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006719 /* Current number of commands waiting for the host. */
6720 len = asc_prt_line(cp, leftlen,
6721 " Total Command Pending: %d\n", v->cur_total_qng);
6722 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006723
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006724 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6725 ASC_PRT_NEXT();
6726 for (i = 0; i <= ASC_MAX_TID; i++) {
6727 if ((chip_scsi_id == i) ||
6728 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6729 continue;
6730 }
6731 len = asc_prt_line(cp, leftlen, " %X:%c",
6732 i,
6733 (v->
6734 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6735 'Y' : 'N');
6736 ASC_PRT_NEXT();
6737 }
6738 len = asc_prt_line(cp, leftlen, "\n");
6739 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006740
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006741 /* Current number of commands waiting for a device. */
6742 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6743 ASC_PRT_NEXT();
6744 for (i = 0; i <= ASC_MAX_TID; i++) {
6745 if ((chip_scsi_id == i) ||
6746 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6747 continue;
6748 }
6749 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6750 ASC_PRT_NEXT();
6751 }
6752 len = asc_prt_line(cp, leftlen, "\n");
6753 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006754
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006755 /* Current limit on number of commands that can be sent to a device. */
6756 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6757 ASC_PRT_NEXT();
6758 for (i = 0; i <= ASC_MAX_TID; i++) {
6759 if ((chip_scsi_id == i) ||
6760 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6761 continue;
6762 }
6763 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
6764 ASC_PRT_NEXT();
6765 }
6766 len = asc_prt_line(cp, leftlen, "\n");
6767 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006769 /* Indicate whether the device has returned queue full status. */
6770 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
6771 ASC_PRT_NEXT();
6772 for (i = 0; i <= ASC_MAX_TID; i++) {
6773 if ((chip_scsi_id == i) ||
6774 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6775 continue;
6776 }
6777 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
6778 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
6779 i, boardp->queue_full_cnt[i]);
6780 } else {
6781 len = asc_prt_line(cp, leftlen, " %X:N", i);
6782 }
6783 ASC_PRT_NEXT();
6784 }
6785 len = asc_prt_line(cp, leftlen, "\n");
6786 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006787
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006788 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6789 ASC_PRT_NEXT();
6790 for (i = 0; i <= ASC_MAX_TID; i++) {
6791 if ((chip_scsi_id == i) ||
6792 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6793 continue;
6794 }
6795 len = asc_prt_line(cp, leftlen, " %X:%c",
6796 i,
6797 (v->
6798 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6799 'N');
6800 ASC_PRT_NEXT();
6801 }
6802 len = asc_prt_line(cp, leftlen, "\n");
6803 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006804
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006805 for (i = 0; i <= ASC_MAX_TID; i++) {
6806 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006807
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006808 if ((chip_scsi_id == i) ||
6809 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6810 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
6811 continue;
6812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006813
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006814 len = asc_prt_line(cp, leftlen, " %X:", i);
6815 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006817 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
6818 len = asc_prt_line(cp, leftlen, " Asynchronous");
6819 ASC_PRT_NEXT();
6820 } else {
6821 syn_period_ix =
6822 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
6823 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006824
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006825 len = asc_prt_line(cp, leftlen,
6826 " Transfer Period Factor: %d (%d.%d Mhz),",
6827 v->sdtr_period_tbl[syn_period_ix],
6828 250 /
6829 v->sdtr_period_tbl[syn_period_ix],
6830 ASC_TENTHS(250,
6831 v->
6832 sdtr_period_tbl
6833 [syn_period_ix]));
6834 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006835
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006836 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6837 boardp->
6838 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
6839 ASC_PRT_NEXT();
6840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006841
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006842 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6843 len = asc_prt_line(cp, leftlen, "*\n");
6844 renegotiate = 1;
6845 } else {
6846 len = asc_prt_line(cp, leftlen, "\n");
6847 }
6848 ASC_PRT_NEXT();
6849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006851 if (renegotiate) {
6852 len = asc_prt_line(cp, leftlen,
6853 " * = Re-negotiation pending before next command.\n");
6854 ASC_PRT_NEXT();
6855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006857 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006858}
6859
6860/*
6861 * asc_prt_adv_board_info()
6862 *
6863 * Print dynamic board configuration information.
6864 *
6865 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6866 * cf. asc_prt_line().
6867 *
6868 * Return the number of characters copied into 'cp'. No more than
6869 * 'cplen' characters will be copied to 'cp'.
6870 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006871static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006872{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006873 asc_board_t *boardp;
6874 int leftlen;
6875 int totlen;
6876 int len;
6877 int i;
6878 ADV_DVC_VAR *v;
6879 ADV_DVC_CFG *c;
6880 AdvPortAddr iop_base;
6881 ushort chip_scsi_id;
6882 ushort lramword;
6883 uchar lrambyte;
6884 ushort tagqng_able;
6885 ushort sdtr_able, wdtr_able;
6886 ushort wdtr_done, sdtr_done;
6887 ushort period = 0;
6888 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006889
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006890 boardp = ASC_BOARDP(shost);
6891 v = &boardp->dvc_var.adv_dvc_var;
6892 c = &boardp->dvc_cfg.adv_dvc_cfg;
6893 iop_base = v->iop_base;
6894 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006895
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006896 leftlen = cplen;
6897 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006898
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006899 len = asc_prt_line(cp, leftlen,
6900 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6901 shost->host_no);
6902 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006903
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006904 len = asc_prt_line(cp, leftlen,
6905 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
6906 v->iop_base,
6907 AdvReadWordRegister(iop_base,
6908 IOPW_SCSI_CFG1) & CABLE_DETECT,
6909 v->err_code);
6910 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006911
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006912 len = asc_prt_line(cp, leftlen,
6913 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
6914 c->chip_version, c->lib_version, c->mcode_date,
6915 c->mcode_version);
6916 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006917
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006918 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
6919 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
6920 ASC_PRT_NEXT();
6921 for (i = 0; i <= ADV_MAX_TID; i++) {
6922 if ((chip_scsi_id == i) ||
6923 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6924 continue;
6925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006926
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006927 len = asc_prt_line(cp, leftlen, " %X:%c",
6928 i,
6929 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6930 'N');
6931 ASC_PRT_NEXT();
6932 }
6933 len = asc_prt_line(cp, leftlen, "\n");
6934 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006935
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006936 len = asc_prt_line(cp, leftlen, " Queue Limit:");
6937 ASC_PRT_NEXT();
6938 for (i = 0; i <= ADV_MAX_TID; i++) {
6939 if ((chip_scsi_id == i) ||
6940 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6941 continue;
6942 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006944 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
6945 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006946
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006947 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6948 ASC_PRT_NEXT();
6949 }
6950 len = asc_prt_line(cp, leftlen, "\n");
6951 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006952
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006953 len = asc_prt_line(cp, leftlen, " Command Pending:");
6954 ASC_PRT_NEXT();
6955 for (i = 0; i <= ADV_MAX_TID; i++) {
6956 if ((chip_scsi_id == i) ||
6957 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6958 continue;
6959 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006960
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006961 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
6962 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006963
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006964 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6965 ASC_PRT_NEXT();
6966 }
6967 len = asc_prt_line(cp, leftlen, "\n");
6968 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006969
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006970 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
6971 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
6972 ASC_PRT_NEXT();
6973 for (i = 0; i <= ADV_MAX_TID; i++) {
6974 if ((chip_scsi_id == i) ||
6975 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6976 continue;
6977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006978
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006979 len = asc_prt_line(cp, leftlen, " %X:%c",
6980 i,
6981 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6982 'N');
6983 ASC_PRT_NEXT();
6984 }
6985 len = asc_prt_line(cp, leftlen, "\n");
6986 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006987
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006988 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
6989 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
6990 ASC_PRT_NEXT();
6991 for (i = 0; i <= ADV_MAX_TID; i++) {
6992 if ((chip_scsi_id == i) ||
6993 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6994 continue;
6995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006997 AdvReadWordLram(iop_base,
6998 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
6999 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007000
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007001 len = asc_prt_line(cp, leftlen, " %X:%d",
7002 i, (lramword & 0x8000) ? 16 : 8);
7003 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007004
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007005 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
7006 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7007 len = asc_prt_line(cp, leftlen, "*");
7008 ASC_PRT_NEXT();
7009 renegotiate = 1;
7010 }
7011 }
7012 len = asc_prt_line(cp, leftlen, "\n");
7013 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007014
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007015 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7016 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7017 ASC_PRT_NEXT();
7018 for (i = 0; i <= ADV_MAX_TID; i++) {
7019 if ((chip_scsi_id == i) ||
7020 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7021 continue;
7022 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007023
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007024 len = asc_prt_line(cp, leftlen, " %X:%c",
7025 i,
7026 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7027 'N');
7028 ASC_PRT_NEXT();
7029 }
7030 len = asc_prt_line(cp, leftlen, "\n");
7031 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007032
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007033 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7034 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007035
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007036 AdvReadWordLram(iop_base,
7037 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7038 lramword);
7039 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007040
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007041 if ((chip_scsi_id == i) ||
7042 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7043 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7044 continue;
7045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007046
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007047 len = asc_prt_line(cp, leftlen, " %X:", i);
7048 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007049
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007050 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7051 len = asc_prt_line(cp, leftlen, " Asynchronous");
7052 ASC_PRT_NEXT();
7053 } else {
7054 len =
7055 asc_prt_line(cp, leftlen,
7056 " Transfer Period Factor: ");
7057 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007058
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007059 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7060 len =
7061 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7062 ASC_PRT_NEXT();
7063 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7064 len =
7065 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7066 ASC_PRT_NEXT();
7067 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007068
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007069 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007070
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007071 if (period == 0) { /* Should never happen. */
7072 len =
7073 asc_prt_line(cp, leftlen,
7074 "%d (? Mhz), ");
7075 ASC_PRT_NEXT();
7076 } else {
7077 len = asc_prt_line(cp, leftlen,
7078 "%d (%d.%d Mhz),",
7079 period, 250 / period,
7080 ASC_TENTHS(250,
7081 period));
7082 ASC_PRT_NEXT();
7083 }
7084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007086 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7087 lramword & 0x1F);
7088 ASC_PRT_NEXT();
7089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007090
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007091 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7092 len = asc_prt_line(cp, leftlen, "*\n");
7093 renegotiate = 1;
7094 } else {
7095 len = asc_prt_line(cp, leftlen, "\n");
7096 }
7097 ASC_PRT_NEXT();
7098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007099
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007100 if (renegotiate) {
7101 len = asc_prt_line(cp, leftlen,
7102 " * = Re-negotiation pending before next command.\n");
7103 ASC_PRT_NEXT();
7104 }
7105
7106 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007107}
7108
7109/*
7110 * asc_proc_copy()
7111 *
7112 * Copy proc information to a read buffer taking into account the current
7113 * read offset in the file and the remaining space in the read buffer.
7114 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007115static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007117 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007118{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007119 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007120
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007121 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7122 (unsigned)offset, (unsigned)advoffset, cplen);
7123 if (offset <= advoffset) {
7124 /* Read offset below current offset, copy everything. */
7125 cnt = min(cplen, leftlen);
7126 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7127 (ulong)curbuf, (ulong)cp, cnt);
7128 memcpy(curbuf, cp, cnt);
7129 } else if (offset < advoffset + cplen) {
7130 /* Read offset within current range, partial copy. */
7131 cnt = (advoffset + cplen) - offset;
7132 cp = (cp + cplen) - cnt;
7133 cnt = min(cnt, leftlen);
7134 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7135 (ulong)curbuf, (ulong)cp, cnt);
7136 memcpy(curbuf, cp, cnt);
7137 }
7138 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007139}
7140
7141/*
7142 * asc_prt_line()
7143 *
7144 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7145 *
7146 * Return 0 if printing to the console, otherwise return the number of
7147 * bytes written to the buffer.
7148 *
7149 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7150 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7151 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007152static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007153{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007154 va_list args;
7155 int ret;
7156 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007157
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007158 va_start(args, fmt);
7159 ret = vsprintf(s, fmt, args);
7160 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7161 if (buf == NULL) {
7162 (void)printk(s);
7163 ret = 0;
7164 } else {
7165 ret = min(buflen, ret);
7166 memcpy(buf, s, ret);
7167 }
7168 va_end(args);
7169 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007170}
7171#endif /* CONFIG_PROC_FS */
7172
Linus Torvalds1da177e2005-04-16 15:20:36 -07007173/*
7174 * --- Functions Required by the Asc Library
7175 */
7176
7177/*
7178 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7179 * global variable which is incremented once every 5 ms
7180 * from a timer interrupt, because this function may be
7181 * called when interrupts are disabled.
7182 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007183static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007184{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007185 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7186 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007187}
7188
7189/*
7190 * Currently and inline noop but leave as a placeholder.
7191 * Leave DvcEnterCritical() as a noop placeholder.
7192 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007193static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007194{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007195 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007196}
7197
7198/*
7199 * Critical sections are all protected by the board spinlock.
7200 * Leave DvcLeaveCritical() as a noop placeholder.
7201 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007202static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007203{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007204 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007205}
7206
7207/*
7208 * void
7209 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7210 *
7211 * Calling/Exit State:
7212 * none
7213 *
7214 * Description:
7215 * Output an ASC_SCSI_Q structure to the chip
7216 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007217static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007218DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7219{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007220 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007221
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007222 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7223 AscSetChipLramAddr(iop_base, s_addr);
7224 for (i = 0; i < 2 * words; i += 2) {
7225 if (i == 4 || i == 20) {
7226 continue;
7227 }
7228 outpw(iop_base + IOP_RAM_DATA,
7229 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007231}
7232
7233/*
7234 * void
7235 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7236 *
7237 * Calling/Exit State:
7238 * none
7239 *
7240 * Description:
7241 * Input an ASC_QDONE_INFO structure from the chip
7242 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007243static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007244DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7245{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007246 int i;
7247 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007248
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007249 AscSetChipLramAddr(iop_base, s_addr);
7250 for (i = 0; i < 2 * words; i += 2) {
7251 if (i == 10) {
7252 continue;
7253 }
7254 word = inpw(iop_base + IOP_RAM_DATA);
7255 inbuf[i] = word & 0xff;
7256 inbuf[i + 1] = (word >> 8) & 0xff;
7257 }
7258 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007259}
7260
7261/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007262 * Return the BIOS address of the adapter at the specified
7263 * I/O port and with the specified bus type.
7264 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007265static unsigned short __devinit
7266AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007267{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007268 unsigned short cfg_lsw;
7269 unsigned short bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007270
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007271 /*
7272 * The PCI BIOS is re-located by the motherboard BIOS. Because
7273 * of this the driver can not determine where a PCI BIOS is
7274 * loaded and executes.
7275 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007276 if (bus_type & ASC_IS_PCI)
7277 return 0;
7278
Linus Torvalds1da177e2005-04-16 15:20:36 -07007279#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007280 if ((bus_type & ASC_IS_EISA) != 0) {
7281 cfg_lsw = AscGetEisaChipCfg(iop_base);
7282 cfg_lsw &= 0x000F;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007283 bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE;
7284 return bios_addr;
7285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007286#endif /* CONFIG_ISA */
7287
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007288 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007289
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007290 /*
7291 * ISA PnP uses the top bit as the 32K BIOS flag
7292 */
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007293 if (bus_type == ASC_IS_ISAPNP)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007294 cfg_lsw &= 0x7FFF;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007295 bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE;
7296 return bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007297}
7298
Linus Torvalds1da177e2005-04-16 15:20:36 -07007299/*
7300 * --- Functions Required by the Adv Library
7301 */
7302
7303/*
7304 * DvcGetPhyAddr()
7305 *
7306 * Return the physical address of 'vaddr' and set '*lenp' to the
7307 * number of physically contiguous bytes that follow 'vaddr'.
7308 * 'flag' indicates the type of structure whose physical address
7309 * is being translated.
7310 *
7311 * Note: Because Linux currently doesn't page the kernel and all
7312 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7313 */
7314ADV_PADDR
7315DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007316 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007317{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007318 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007320 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007321
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007322 ASC_DBG4(4,
7323 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7324 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7325 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007326
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007327 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007328}
7329
7330/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007331 * --- Tracing and Debugging Functions
7332 */
7333
7334#ifdef ADVANSYS_STATS
7335#ifdef CONFIG_PROC_FS
7336/*
7337 * asc_prt_board_stats()
7338 *
7339 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7340 * cf. asc_prt_line().
7341 *
7342 * Return the number of characters copied into 'cp'. No more than
7343 * 'cplen' characters will be copied to 'cp'.
7344 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007345static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007346{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007347 int leftlen;
7348 int totlen;
7349 int len;
7350 struct asc_stats *s;
7351 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007353 leftlen = cplen;
7354 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007355
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007356 boardp = ASC_BOARDP(shost);
7357 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007358
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007359 len = asc_prt_line(cp, leftlen,
7360 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7361 shost->host_no);
7362 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007363
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007364 len = asc_prt_line(cp, leftlen,
7365 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7366 s->queuecommand, s->reset, s->biosparam,
7367 s->interrupt);
7368 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007369
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007370 len = asc_prt_line(cp, leftlen,
7371 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7372 s->callback, s->done, s->build_error,
7373 s->adv_build_noreq, s->adv_build_nosg);
7374 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007375
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007376 len = asc_prt_line(cp, leftlen,
7377 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7378 s->exe_noerror, s->exe_busy, s->exe_error,
7379 s->exe_unknown);
7380 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007382 /*
7383 * Display data transfer statistics.
7384 */
7385 if (s->cont_cnt > 0) {
7386 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7387 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007388
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007389 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7390 s->cont_xfer / 2,
7391 ASC_TENTHS(s->cont_xfer, 2));
7392 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007394 /* Contiguous transfer average size */
7395 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7396 (s->cont_xfer / 2) / s->cont_cnt,
7397 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7398 ASC_PRT_NEXT();
7399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007400
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007401 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007403 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7404 s->sg_cnt, s->sg_elem);
7405 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007406
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007407 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7408 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7409 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007410
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007411 /* Scatter gather transfer statistics */
7412 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7413 s->sg_elem / s->sg_cnt,
7414 ASC_TENTHS(s->sg_elem, s->sg_cnt));
7415 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007416
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007417 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
7418 (s->sg_xfer / 2) / s->sg_elem,
7419 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7420 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007421
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007422 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7423 (s->sg_xfer / 2) / s->sg_cnt,
7424 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7425 ASC_PRT_NEXT();
7426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007428 /*
7429 * Display request queuing statistics.
7430 */
7431 len = asc_prt_line(cp, leftlen,
7432 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7433 HZ);
7434 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007436 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007437}
7438
7439/*
7440 * asc_prt_target_stats()
7441 *
7442 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7443 * cf. asc_prt_line().
7444 *
7445 * This is separated from asc_prt_board_stats because a full set
7446 * of targets will overflow ASC_PRTBUF_SIZE.
7447 *
7448 * Return the number of characters copied into 'cp'. No more than
7449 * 'cplen' characters will be copied to 'cp'.
7450 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007451static int
7452asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007453{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007454 int leftlen;
7455 int totlen;
7456 int len;
7457 struct asc_stats *s;
7458 ushort chip_scsi_id;
7459 asc_board_t *boardp;
7460 asc_queue_t *active;
7461 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007462
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007463 leftlen = cplen;
7464 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007465
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007466 boardp = ASC_BOARDP(shost);
7467 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007468
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007469 active = &ASC_BOARDP(shost)->active;
7470 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007471
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007472 if (ASC_NARROW_BOARD(boardp)) {
7473 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7474 } else {
7475 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007477
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007478 if ((chip_scsi_id == tgt_id) ||
7479 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7480 return 0;
7481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007482
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007483 do {
7484 if (active->q_tot_cnt[tgt_id] > 0
7485 || waiting->q_tot_cnt[tgt_id] > 0) {
7486 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
7487 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007488
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007489 len = asc_prt_line(cp, leftlen,
7490 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7491 active->q_cur_cnt[tgt_id],
7492 active->q_max_cnt[tgt_id],
7493 active->q_tot_cnt[tgt_id],
7494 active->q_min_tim[tgt_id],
7495 active->q_max_tim[tgt_id],
7496 (active->q_tot_cnt[tgt_id] ==
7497 0) ? 0 : (active->
7498 q_tot_tim[tgt_id] /
7499 active->
7500 q_tot_cnt[tgt_id]),
7501 (active->q_tot_cnt[tgt_id] ==
7502 0) ? 0 : ASC_TENTHS(active->
7503 q_tot_tim
7504 [tgt_id],
7505 active->
7506 q_tot_cnt
7507 [tgt_id]));
7508 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007509
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007510 len = asc_prt_line(cp, leftlen,
7511 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7512 waiting->q_cur_cnt[tgt_id],
7513 waiting->q_max_cnt[tgt_id],
7514 waiting->q_tot_cnt[tgt_id],
7515 waiting->q_min_tim[tgt_id],
7516 waiting->q_max_tim[tgt_id],
7517 (waiting->q_tot_cnt[tgt_id] ==
7518 0) ? 0 : (waiting->
7519 q_tot_tim[tgt_id] /
7520 waiting->
7521 q_tot_cnt[tgt_id]),
7522 (waiting->q_tot_cnt[tgt_id] ==
7523 0) ? 0 : ASC_TENTHS(waiting->
7524 q_tot_tim
7525 [tgt_id],
7526 waiting->
7527 q_tot_cnt
7528 [tgt_id]));
7529 ASC_PRT_NEXT();
7530 }
7531 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007532
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007533 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007534}
7535#endif /* CONFIG_PROC_FS */
7536#endif /* ADVANSYS_STATS */
7537
7538#ifdef ADVANSYS_DEBUG
7539/*
7540 * asc_prt_scsi_host()
7541 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007542static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007543{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007544 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007545
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007546 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007547
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007548 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7549 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7550 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007551
Matthew Wilcox4a2d31c2007-07-26 11:55:34 -04007552 printk(" base 0x%lx, io_port 0x%lx, irq 0x%x,\n",
7553 (ulong)s->base, (ulong)s->io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007554
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007555 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7556 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007557
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007558 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7559 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007560
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007561 if (ASC_NARROW_BOARD(boardp)) {
7562 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7563 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7564 } else {
7565 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7566 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007568}
7569
7570/*
7571 * asc_prt_scsi_cmnd()
7572 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007573static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007574{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007575 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007576
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007577 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7578 (ulong)s->device->host, (ulong)s->device, s->device->id,
7579 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007580
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007581 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007582
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007583 printk("sc_data_direction %u, resid %d\n",
7584 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007585
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007586 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007587
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007588 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7589 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007590
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007591 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007592
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007593 printk(" scsi_done 0x%p, done 0x%p, host_scribble 0x%p, result 0x%x\n",
7594 s->scsi_done, s->done, s->host_scribble, s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007595
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007596 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007597}
7598
7599/*
7600 * asc_prt_asc_dvc_var()
7601 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007602static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007603{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007604 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007605
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007606 printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl "
7607 "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007608
Matthew Wilcox895d6b42007-07-26 11:57:06 -04007609 printk(" bus_type %d, init_sdtr 0x%x,\n", h->bus_type,
7610 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007611
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007612 printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, "
7613 "chip_no 0x%x,\n", (unsigned)h->sdtr_done,
7614 (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready,
7615 (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007616
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007617 printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait "
7618 "%u,\n", (unsigned)h->queue_full_or_busy,
7619 (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007620
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007621 printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, "
7622 "in_critical_cnt %u,\n", (unsigned)h->is_in_int,
7623 (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng,
7624 (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007625
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007626 printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, "
7627 "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage,
7628 (unsigned)h->init_state, (unsigned)h->no_scam,
7629 (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007630
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007631 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007632}
7633
7634/*
7635 * asc_prt_asc_dvc_cfg()
7636 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007637static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007638{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007639 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007641 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7642 h->can_tagged_qng, h->cmd_qng_enabled);
7643 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7644 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007645
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007646 printk
7647 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7648 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7649 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007650
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007651 printk
7652 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7653 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7654 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007655
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007656 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7657 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007658}
7659
7660/*
7661 * asc_prt_asc_scsi_q()
7662 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007663static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007664{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007665 ASC_SG_HEAD *sgp;
7666 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007668 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007670 printk
7671 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7672 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7673 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007675 printk
7676 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7677 (ulong)le32_to_cpu(q->q1.data_addr),
7678 (ulong)le32_to_cpu(q->q1.data_cnt),
7679 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007680
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007681 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
7682 (ulong)q->cdbptr, q->q2.cdb_len,
7683 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007684
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007685 if (q->sg_head) {
7686 sgp = q->sg_head;
7687 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
7688 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
7689 sgp->queue_cnt);
7690 for (i = 0; i < sgp->entry_cnt; i++) {
7691 printk(" [%u]: addr 0x%lx, bytes %lu\n",
7692 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
7693 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
7694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007695
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007697}
7698
7699/*
7700 * asc_prt_asc_qdone_info()
7701 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007702static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007703{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007704 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
7705 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
7706 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
7707 q->d2.tag_code);
7708 printk
7709 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
7710 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007711}
7712
7713/*
7714 * asc_prt_adv_dvc_var()
7715 *
7716 * Display an ADV_DVC_VAR structure.
7717 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007718static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007719{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007720 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007721
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007722 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
7723 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007724
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007725 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
7726 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
7727 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007728
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007729 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
7730 (unsigned)h->start_motor,
7731 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007732
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007733 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
7734 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
7735 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007736
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007737 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
7738 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007739
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007740 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
7741 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007742
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007743 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
7744 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007745}
7746
7747/*
7748 * asc_prt_adv_dvc_cfg()
7749 *
7750 * Display an ADV_DVC_CFG structure.
7751 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007752static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007753{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007754 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007755
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007756 printk(" disc_enable 0x%x, termination 0x%x\n",
7757 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007758
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007759 printk(" chip_version 0x%x, mcode_date 0x%x\n",
7760 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007762 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
7763 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007764
Matthew Wilcox13ac2d92007-07-30 08:10:23 -06007765 printk(" control_flag 0x%x\n", h->control_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007766}
7767
7768/*
7769 * asc_prt_adv_scsi_req_q()
7770 *
7771 * Display an ADV_SCSI_REQ_Q structure.
7772 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007773static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007774{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007775 int sg_blk_cnt;
7776 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007777
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007778 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007779
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007780 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
7781 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007782
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007783 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
7784 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007785
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007786 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7787 (ulong)le32_to_cpu(q->data_cnt),
7788 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007790 printk
7791 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
7792 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007793
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007794 printk(" sg_working_ix 0x%x, target_cmd %u\n",
7795 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007796
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007797 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
7798 (ulong)le32_to_cpu(q->scsiq_rptr),
7799 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007800
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007801 /* Display the request's ADV_SG_BLOCK structures. */
7802 if (q->sg_list_ptr != NULL) {
7803 sg_blk_cnt = 0;
7804 while (1) {
7805 /*
7806 * 'sg_ptr' is a physical address. Convert it to a virtual
7807 * address by indexing 'sg_blk_cnt' into the virtual address
7808 * array 'sg_list_ptr'.
7809 *
7810 * XXX - Assumes all SG physical blocks are virtually contiguous.
7811 */
7812 sg_ptr =
7813 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
7814 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
7815 if (sg_ptr->sg_ptr == 0) {
7816 break;
7817 }
7818 sg_blk_cnt++;
7819 }
7820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007821}
7822
7823/*
7824 * asc_prt_adv_sgblock()
7825 *
7826 * Display an ADV_SG_BLOCK structure.
7827 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007828static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007829{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007830 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007832 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
7833 (ulong)b, sgblockno);
7834 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
7835 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
7836 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
7837 if (b->sg_ptr != 0) {
7838 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
7839 }
7840 for (i = 0; i < b->sg_cnt; i++) {
7841 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
7842 i, (ulong)b->sg_list[i].sg_addr,
7843 (ulong)b->sg_list[i].sg_count);
7844 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007845}
7846
7847/*
7848 * asc_prt_hex()
7849 *
7850 * Print hexadecimal output in 4 byte groupings 32 bytes
7851 * or 8 double-words per line.
7852 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007853static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007854{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007855 int i;
7856 int j;
7857 int k;
7858 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007859
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007860 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007861
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007862 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007863
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007864 /* Display a maximum of 8 double-words per line. */
7865 if ((k = (l - i) / 4) >= 8) {
7866 k = 8;
7867 m = 0;
7868 } else {
7869 m = (l - i) % 4;
7870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007871
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007872 for (j = 0; j < k; j++) {
7873 printk(" %2.2X%2.2X%2.2X%2.2X",
7874 (unsigned)s[i + (j * 4)],
7875 (unsigned)s[i + (j * 4) + 1],
7876 (unsigned)s[i + (j * 4) + 2],
7877 (unsigned)s[i + (j * 4) + 3]);
7878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007880 switch (m) {
7881 case 0:
7882 default:
7883 break;
7884 case 1:
7885 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
7886 break;
7887 case 2:
7888 printk(" %2.2X%2.2X",
7889 (unsigned)s[i + (j * 4)],
7890 (unsigned)s[i + (j * 4) + 1]);
7891 break;
7892 case 3:
7893 printk(" %2.2X%2.2X%2.2X",
7894 (unsigned)s[i + (j * 4) + 1],
7895 (unsigned)s[i + (j * 4) + 2],
7896 (unsigned)s[i + (j * 4) + 3]);
7897 break;
7898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007899
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007900 printk("\n");
7901 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007902}
7903#endif /* ADVANSYS_DEBUG */
7904
7905/*
7906 * --- Asc Library Functions
7907 */
7908
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007909static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007910{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007911 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007912
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007913 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7914 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
7915 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007916}
7917
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007918static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007919{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007920 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007921
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007922 if (AscGetChipScsiID(iop_base) == new_host_id) {
7923 return (new_host_id);
7924 }
7925 cfg_lsw = AscGetChipCfgLsw(iop_base);
7926 cfg_lsw &= 0xF8FF;
7927 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
7928 AscSetChipCfgLsw(iop_base, cfg_lsw);
7929 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007930}
7931
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007932static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007933{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007934 unsigned char sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007935
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007936 AscSetBank(iop_base, 1);
7937 sc = inp(iop_base + IOP_REG_SC);
7938 AscSetBank(iop_base, 0);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007939 return sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007940}
7941
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007942static unsigned char __devinit
7943AscGetChipVersion(PortAddr iop_base, unsigned short bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007944{
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007945 if (bus_type & ASC_IS_EISA) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007946 PortAddr eisa_iop;
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007947 unsigned char revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007948 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7949 (PortAddr) ASC_EISA_REV_IOP_MASK;
7950 revision = inp(eisa_iop);
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007951 return ASC_CHIP_MIN_VER_EISA - 1 + revision;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007952 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -06007953 return AscGetChipVerNo(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007954}
7955
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007956static ASC_DCNT
7957AscLoadMicroCode(PortAddr iop_base,
7958 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007959{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007960 ASC_DCNT chksum;
7961 ushort mcode_word_size;
7962 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007963
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007964 /* Write the microcode buffer starting at LRAM address 0. */
7965 mcode_word_size = (ushort)(mcode_size >> 1);
7966 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
7967 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007968
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007969 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
7970 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
7971 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
7972 (ushort)ASC_CODE_SEC_BEG,
7973 (ushort)((mcode_size -
7974 s_addr - (ushort)
7975 ASC_CODE_SEC_BEG) /
7976 2));
7977 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
7978 (ulong)mcode_chksum);
7979 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
7980 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
7981 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007982}
7983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007984static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007985{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007986 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007987
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007988 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
7989 iop_base, AscGetChipSignatureByte(iop_base));
7990 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
7991 ASC_DBG2(1,
7992 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
7993 iop_base, AscGetChipSignatureWord(iop_base));
7994 sig_word = AscGetChipSignatureWord(iop_base);
7995 if ((sig_word == (ushort)ASC_1000_ID0W) ||
7996 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
7997 return (1);
7998 }
7999 }
8000 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008001}
8002
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008003static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008004{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008005 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
8006 AscSetChipStatus(iop_base, 0);
8007 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008008}
8009
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008010static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008011{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008012 ushort cfg_lsw;
8013 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008014
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008015 if ((bus_type & ASC_IS_EISA) != 0) {
8016 cfg_lsw = AscGetEisaChipCfg(iop_base);
8017 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8018 if ((chip_irq == 13) || (chip_irq > 15)) {
8019 return (0);
8020 }
8021 return (chip_irq);
8022 }
8023 if ((bus_type & ASC_IS_VL) != 0) {
8024 cfg_lsw = AscGetChipCfgLsw(iop_base);
8025 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8026 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8027 return (0);
8028 }
8029 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8030 }
8031 cfg_lsw = AscGetChipCfgLsw(iop_base);
8032 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8033 if (chip_irq == 3)
8034 chip_irq += (uchar)2;
8035 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008036}
8037
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008038static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008039AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008040{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008041 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008042
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008043 if ((bus_type & ASC_IS_VL) != 0) {
8044 if (irq_no != 0) {
8045 if ((irq_no < ASC_MIN_IRQ_NO)
8046 || (irq_no > ASC_MAX_IRQ_NO)) {
8047 irq_no = 0;
8048 } else {
8049 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8050 }
8051 }
8052 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8053 cfg_lsw |= (ushort)0x0010;
8054 AscSetChipCfgLsw(iop_base, cfg_lsw);
8055 AscToggleIRQAct(iop_base);
8056 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8057 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8058 AscSetChipCfgLsw(iop_base, cfg_lsw);
8059 AscToggleIRQAct(iop_base);
8060 return (AscGetChipIRQ(iop_base, bus_type));
8061 }
8062 if ((bus_type & (ASC_IS_ISA)) != 0) {
8063 if (irq_no == 15)
8064 irq_no -= (uchar)2;
8065 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8066 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8067 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8068 AscSetChipCfgLsw(iop_base, cfg_lsw);
8069 return (AscGetChipIRQ(iop_base, bus_type));
8070 }
8071 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008072}
8073
8074#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008075static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008076{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008077 if (dma_channel < 4) {
8078 outp(0x000B, (ushort)(0xC0 | dma_channel));
8079 outp(0x000A, dma_channel);
8080 } else if (dma_channel < 8) {
8081 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8082 outp(0x00D4, (ushort)(dma_channel - 4));
8083 }
8084 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008085}
8086#endif /* CONFIG_ISA */
8087
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008088static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008089{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008090 EXT_MSG ext_msg;
8091 EXT_MSG out_msg;
8092 ushort halt_q_addr;
8093 int sdtr_accept;
8094 ushort int_halt_code;
8095 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8096 ASC_SCSI_BIT_ID_TYPE target_id;
8097 PortAddr iop_base;
8098 uchar tag_code;
8099 uchar q_status;
8100 uchar halt_qp;
8101 uchar sdtr_data;
8102 uchar target_ix;
8103 uchar q_cntl, tid_no;
8104 uchar cur_dvc_qng;
8105 uchar asyn_sdtr;
8106 uchar scsi_status;
8107 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008108
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008109 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8110 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008111
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008112 iop_base = asc_dvc->iop_base;
8113 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008114
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008115 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8116 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8117 target_ix = AscReadLramByte(iop_base,
8118 (ushort)(halt_q_addr +
8119 (ushort)ASC_SCSIQ_B_TARGET_IX));
8120 q_cntl =
8121 AscReadLramByte(iop_base,
8122 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8123 tid_no = ASC_TIX_TO_TID(target_ix);
8124 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8125 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8126 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8127 } else {
8128 asyn_sdtr = 0;
8129 }
8130 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8131 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8132 AscSetChipSDTR(iop_base, 0, tid_no);
8133 boardp->sdtr_data[tid_no] = 0;
8134 }
8135 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8136 return (0);
8137 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8138 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8139 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8140 boardp->sdtr_data[tid_no] = asyn_sdtr;
8141 }
8142 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8143 return (0);
8144 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008145
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008146 AscMemWordCopyPtrFromLram(iop_base,
8147 ASCV_MSGIN_BEG,
8148 (uchar *)&ext_msg,
8149 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008150
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008151 if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8152 ext_msg.msg_req == EXTENDED_SDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008153 ext_msg.msg_len == MS_SDTR_LEN) {
8154 sdtr_accept = TRUE;
8155 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008157 sdtr_accept = FALSE;
8158 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8159 }
8160 if ((ext_msg.xfer_period <
8161 asc_dvc->sdtr_period_tbl[asc_dvc->
8162 host_init_sdtr_index])
8163 || (ext_msg.xfer_period >
8164 asc_dvc->sdtr_period_tbl[asc_dvc->
8165 max_sdtr_index])) {
8166 sdtr_accept = FALSE;
8167 ext_msg.xfer_period =
8168 asc_dvc->sdtr_period_tbl[asc_dvc->
8169 host_init_sdtr_index];
8170 }
8171 if (sdtr_accept) {
8172 sdtr_data =
8173 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8174 ext_msg.req_ack_offset);
8175 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008176
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008177 q_cntl |= QC_MSG_OUT;
8178 asc_dvc->init_sdtr &= ~target_id;
8179 asc_dvc->sdtr_done &= ~target_id;
8180 AscSetChipSDTR(iop_base, asyn_sdtr,
8181 tid_no);
8182 boardp->sdtr_data[tid_no] = asyn_sdtr;
8183 }
8184 }
8185 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008186
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008187 q_cntl &= ~QC_MSG_OUT;
8188 asc_dvc->init_sdtr &= ~target_id;
8189 asc_dvc->sdtr_done &= ~target_id;
8190 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8191 } else {
8192 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008193
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008194 q_cntl &= ~QC_MSG_OUT;
8195 asc_dvc->sdtr_done |= target_id;
8196 asc_dvc->init_sdtr |= target_id;
8197 asc_dvc->pci_fix_asyn_xfer &=
8198 ~target_id;
8199 sdtr_data =
8200 AscCalSDTRData(asc_dvc,
8201 ext_msg.xfer_period,
8202 ext_msg.
8203 req_ack_offset);
8204 AscSetChipSDTR(iop_base, sdtr_data,
8205 tid_no);
8206 boardp->sdtr_data[tid_no] = sdtr_data;
8207 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008208
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008209 q_cntl |= QC_MSG_OUT;
8210 AscMsgOutSDTR(asc_dvc,
8211 ext_msg.xfer_period,
8212 ext_msg.req_ack_offset);
8213 asc_dvc->pci_fix_asyn_xfer &=
8214 ~target_id;
8215 sdtr_data =
8216 AscCalSDTRData(asc_dvc,
8217 ext_msg.xfer_period,
8218 ext_msg.
8219 req_ack_offset);
8220 AscSetChipSDTR(iop_base, sdtr_data,
8221 tid_no);
8222 boardp->sdtr_data[tid_no] = sdtr_data;
8223 asc_dvc->sdtr_done |= target_id;
8224 asc_dvc->init_sdtr |= target_id;
8225 }
8226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008227
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008228 AscWriteLramByte(iop_base,
8229 (ushort)(halt_q_addr +
8230 (ushort)ASC_SCSIQ_B_CNTL),
8231 q_cntl);
8232 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8233 return (0);
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008234 } else if (ext_msg.msg_type == EXTENDED_MESSAGE &&
8235 ext_msg.msg_req == EXTENDED_WDTR &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008236 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008237
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008238 ext_msg.wdtr_width = 0;
8239 AscMemWordCopyPtrToLram(iop_base,
8240 ASCV_MSGOUT_BEG,
8241 (uchar *)&ext_msg,
8242 sizeof(EXT_MSG) >> 1);
8243 q_cntl |= QC_MSG_OUT;
8244 AscWriteLramByte(iop_base,
8245 (ushort)(halt_q_addr +
8246 (ushort)ASC_SCSIQ_B_CNTL),
8247 q_cntl);
8248 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8249 return (0);
8250 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008251
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008252 ext_msg.msg_type = MESSAGE_REJECT;
8253 AscMemWordCopyPtrToLram(iop_base,
8254 ASCV_MSGOUT_BEG,
8255 (uchar *)&ext_msg,
8256 sizeof(EXT_MSG) >> 1);
8257 q_cntl |= QC_MSG_OUT;
8258 AscWriteLramByte(iop_base,
8259 (ushort)(halt_q_addr +
8260 (ushort)ASC_SCSIQ_B_CNTL),
8261 q_cntl);
8262 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8263 return (0);
8264 }
8265 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008266
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008267 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008268
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008269 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008270
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008271 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008272
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008273 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8274 q_cntl |= QC_MSG_OUT;
8275 AscMsgOutSDTR(asc_dvc,
8276 asc_dvc->
8277 sdtr_period_tbl[(sdtr_data >> 4) &
8278 (uchar)(asc_dvc->
8279 max_sdtr_index -
8280 1)],
8281 (uchar)(sdtr_data & (uchar)
8282 ASC_SYN_MAX_OFFSET));
8283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008285 AscWriteLramByte(iop_base,
8286 (ushort)(halt_q_addr +
8287 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008288
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008289 tag_code = AscReadLramByte(iop_base,
8290 (ushort)(halt_q_addr + (ushort)
8291 ASC_SCSIQ_B_TAG_CODE));
8292 tag_code &= 0xDC;
8293 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8294 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8295 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008296
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008297 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8298 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008299
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008300 }
8301 AscWriteLramByte(iop_base,
8302 (ushort)(halt_q_addr +
8303 (ushort)ASC_SCSIQ_B_TAG_CODE),
8304 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008305
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008306 q_status = AscReadLramByte(iop_base,
8307 (ushort)(halt_q_addr + (ushort)
8308 ASC_SCSIQ_B_STATUS));
8309 q_status |= (QS_READY | QS_BUSY);
8310 AscWriteLramByte(iop_base,
8311 (ushort)(halt_q_addr +
8312 (ushort)ASC_SCSIQ_B_STATUS),
8313 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008315 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8316 scsi_busy &= ~target_id;
8317 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008318
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008319 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8320 return (0);
8321 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008322
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008323 AscMemWordCopyPtrFromLram(iop_base,
8324 ASCV_MSGOUT_BEG,
8325 (uchar *)&out_msg,
8326 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008327
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008328 if ((out_msg.msg_type == EXTENDED_MESSAGE) &&
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008329 (out_msg.msg_len == MS_SDTR_LEN) &&
Matthew Wilcox47d853c2007-07-26 11:41:33 -04008330 (out_msg.msg_req == EXTENDED_SDTR)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008331
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008332 asc_dvc->init_sdtr &= ~target_id;
8333 asc_dvc->sdtr_done &= ~target_id;
8334 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8335 boardp->sdtr_data[tid_no] = asyn_sdtr;
8336 }
8337 q_cntl &= ~QC_MSG_OUT;
8338 AscWriteLramByte(iop_base,
8339 (ushort)(halt_q_addr +
8340 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8341 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8342 return (0);
8343 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008344
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008345 scsi_status = AscReadLramByte(iop_base,
8346 (ushort)((ushort)halt_q_addr +
8347 (ushort)
8348 ASC_SCSIQ_SCSI_STATUS));
8349 cur_dvc_qng =
8350 AscReadLramByte(iop_base,
8351 (ushort)((ushort)ASC_QADR_BEG +
8352 (ushort)target_ix));
8353 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008354
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008355 scsi_busy = AscReadLramByte(iop_base,
8356 (ushort)ASCV_SCSIBUSY_B);
8357 scsi_busy |= target_id;
8358 AscWriteLramByte(iop_base,
8359 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8360 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008361
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008362 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8363 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8364 cur_dvc_qng -= 1;
8365 asc_dvc->max_dvc_qng[tid_no] =
8366 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008367
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008368 AscWriteLramByte(iop_base,
8369 (ushort)((ushort)
8370 ASCV_MAX_DVC_QNG_BEG
8371 + (ushort)
8372 tid_no),
8373 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008374
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008375 /*
8376 * Set the device queue depth to the number of
8377 * active requests when the QUEUE FULL condition
8378 * was encountered.
8379 */
8380 boardp->queue_full |= target_id;
8381 boardp->queue_full_cnt[tid_no] =
8382 cur_dvc_qng;
8383 }
8384 }
8385 }
8386 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8387 return (0);
8388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008389#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008390 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8391 uchar q_no;
8392 ushort q_addr;
8393 uchar sg_wk_q_no;
8394 uchar first_sg_wk_q_no;
8395 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8396 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8397 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8398 ushort sg_list_dwords;
8399 ushort sg_entry_cnt;
8400 uchar next_qp;
8401 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008403 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8404 if (q_no == ASC_QLINK_END) {
8405 return (0);
8406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008408 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008410 /*
8411 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8412 * structure pointer using a macro provided by the driver.
8413 * The ASC_SCSI_REQ pointer provides a pointer to the
8414 * host ASC_SG_HEAD structure.
8415 */
8416 /* Read request's SRB pointer. */
8417 scsiq = (ASC_SCSI_Q *)
8418 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8419 (ushort)
8420 (q_addr +
8421 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008422
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008423 /*
8424 * Get request's first and working SG queue.
8425 */
8426 sg_wk_q_no = AscReadLramByte(iop_base,
8427 (ushort)(q_addr +
8428 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008429
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008430 first_sg_wk_q_no = AscReadLramByte(iop_base,
8431 (ushort)(q_addr +
8432 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008433
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008434 /*
8435 * Reset request's working SG queue back to the
8436 * first SG queue.
8437 */
8438 AscWriteLramByte(iop_base,
8439 (ushort)(q_addr +
8440 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8441 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008443 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008444
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008445 /*
8446 * Set sg_entry_cnt to the number of SG elements
8447 * that will be completed on this interrupt.
8448 *
8449 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8450 * SG elements. The data_cnt and data_addr fields which
8451 * add 1 to the SG element capacity are not used when
8452 * restarting SG handling after a halt.
8453 */
8454 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8455 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008457 /*
8458 * Keep track of remaining number of SG elements that will
8459 * need to be handled on the next interrupt.
8460 */
8461 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8462 } else {
8463 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8464 scsiq->remain_sg_entry_cnt = 0;
8465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008466
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008467 /*
8468 * Copy SG elements into the list of allocated SG queues.
8469 *
8470 * Last index completed is saved in scsiq->next_sg_index.
8471 */
8472 next_qp = first_sg_wk_q_no;
8473 q_addr = ASC_QNO_TO_QADDR(next_qp);
8474 scsi_sg_q.sg_head_qp = q_no;
8475 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8476 for (i = 0; i < sg_head->queue_cnt; i++) {
8477 scsi_sg_q.seq_no = i + 1;
8478 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8479 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8480 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8481 /*
8482 * After very first SG queue RISC FW uses next
8483 * SG queue first element then checks sg_list_cnt
8484 * against zero and then decrements, so set
8485 * sg_list_cnt 1 less than number of SG elements
8486 * in each SG queue.
8487 */
8488 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8489 scsi_sg_q.sg_cur_list_cnt =
8490 ASC_SG_LIST_PER_Q - 1;
8491 } else {
8492 /*
8493 * This is the last SG queue in the list of
8494 * allocated SG queues. If there are more
8495 * SG elements than will fit in the allocated
8496 * queues, then set the QCSG_SG_XFER_MORE flag.
8497 */
8498 if (scsiq->remain_sg_entry_cnt != 0) {
8499 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8500 } else {
8501 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8502 }
8503 /* equals sg_entry_cnt * 2 */
8504 sg_list_dwords = sg_entry_cnt << 1;
8505 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8506 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8507 sg_entry_cnt = 0;
8508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008509
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008510 scsi_sg_q.q_no = next_qp;
8511 AscMemWordCopyPtrToLram(iop_base,
8512 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8513 (uchar *)&scsi_sg_q,
8514 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008515
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008516 AscMemDWordCopyPtrToLram(iop_base,
8517 q_addr + ASC_SGQ_LIST_BEG,
8518 (uchar *)&sg_head->
8519 sg_list[scsiq->next_sg_index],
8520 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008521
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008522 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008523
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008524 /*
8525 * If the just completed SG queue contained the
8526 * last SG element, then no more SG queues need
8527 * to be written.
8528 */
8529 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8530 break;
8531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008532
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008533 next_qp = AscReadLramByte(iop_base,
8534 (ushort)(q_addr +
8535 ASC_SCSIQ_B_FWD));
8536 q_addr = ASC_QNO_TO_QADDR(next_qp);
8537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008538
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008539 /*
8540 * Clear the halt condition so the RISC will be restarted
8541 * after the return.
8542 */
8543 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8544 return (0);
8545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008546#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008547 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008548}
8549
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008550static uchar
8551_AscCopyLramScsiDoneQ(PortAddr iop_base,
8552 ushort q_addr,
8553 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008554{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008555 ushort _val;
8556 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008557
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008558 DvcGetQinfo(iop_base,
8559 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8560 (uchar *)scsiq,
8561 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008562
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008563 _val = AscReadLramWord(iop_base,
8564 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8565 scsiq->q_status = (uchar)_val;
8566 scsiq->q_no = (uchar)(_val >> 8);
8567 _val = AscReadLramWord(iop_base,
8568 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8569 scsiq->cntl = (uchar)_val;
8570 sg_queue_cnt = (uchar)(_val >> 8);
8571 _val = AscReadLramWord(iop_base,
8572 (ushort)(q_addr +
8573 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8574 scsiq->sense_len = (uchar)_val;
8575 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008576
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008577 /*
8578 * Read high word of remain bytes from alternate location.
8579 */
8580 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
8581 (ushort)(q_addr +
8582 (ushort)
8583 ASC_SCSIQ_W_ALT_DC1)))
8584 << 16);
8585 /*
8586 * Read low word of remain bytes from original location.
8587 */
8588 scsiq->remain_bytes += AscReadLramWord(iop_base,
8589 (ushort)(q_addr + (ushort)
8590 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008592 scsiq->remain_bytes &= max_dma_count;
8593 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008594}
8595
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008596static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008597{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008598 uchar next_qp;
8599 uchar n_q_used;
8600 uchar sg_list_qp;
8601 uchar sg_queue_cnt;
8602 uchar q_cnt;
8603 uchar done_q_tail;
8604 uchar tid_no;
8605 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8606 ASC_SCSI_BIT_ID_TYPE target_id;
8607 PortAddr iop_base;
8608 ushort q_addr;
8609 ushort sg_q_addr;
8610 uchar cur_target_qng;
8611 ASC_QDONE_INFO scsiq_buf;
8612 ASC_QDONE_INFO *scsiq;
8613 int false_overrun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008614
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008615 iop_base = asc_dvc->iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008616 n_q_used = 1;
8617 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
8618 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
8619 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
8620 next_qp = AscReadLramByte(iop_base,
8621 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
8622 if (next_qp != ASC_QLINK_END) {
8623 AscPutVarDoneQTail(iop_base, next_qp);
8624 q_addr = ASC_QNO_TO_QADDR(next_qp);
8625 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
8626 asc_dvc->max_dma_count);
8627 AscWriteLramByte(iop_base,
8628 (ushort)(q_addr +
8629 (ushort)ASC_SCSIQ_B_STATUS),
8630 (uchar)(scsiq->
8631 q_status & (uchar)~(QS_READY |
8632 QS_ABORTED)));
8633 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
8634 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
8635 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
8636 sg_q_addr = q_addr;
8637 sg_list_qp = next_qp;
8638 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
8639 sg_list_qp = AscReadLramByte(iop_base,
8640 (ushort)(sg_q_addr
8641 + (ushort)
8642 ASC_SCSIQ_B_FWD));
8643 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
8644 if (sg_list_qp == ASC_QLINK_END) {
8645 AscSetLibErrorCode(asc_dvc,
8646 ASCQ_ERR_SG_Q_LINKS);
8647 scsiq->d3.done_stat = QD_WITH_ERROR;
8648 scsiq->d3.host_stat =
8649 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
8650 goto FATAL_ERR_QDONE;
8651 }
8652 AscWriteLramByte(iop_base,
8653 (ushort)(sg_q_addr + (ushort)
8654 ASC_SCSIQ_B_STATUS),
8655 QS_FREE);
8656 }
8657 n_q_used = sg_queue_cnt + 1;
8658 AscPutVarDoneQTail(iop_base, sg_list_qp);
8659 }
8660 if (asc_dvc->queue_full_or_busy & target_id) {
8661 cur_target_qng = AscReadLramByte(iop_base,
8662 (ushort)((ushort)
8663 ASC_QADR_BEG
8664 + (ushort)
8665 scsiq->d2.
8666 target_ix));
8667 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
8668 scsi_busy = AscReadLramByte(iop_base, (ushort)
8669 ASCV_SCSIBUSY_B);
8670 scsi_busy &= ~target_id;
8671 AscWriteLramByte(iop_base,
8672 (ushort)ASCV_SCSIBUSY_B,
8673 scsi_busy);
8674 asc_dvc->queue_full_or_busy &= ~target_id;
8675 }
8676 }
8677 if (asc_dvc->cur_total_qng >= n_q_used) {
8678 asc_dvc->cur_total_qng -= n_q_used;
8679 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
8680 asc_dvc->cur_dvc_qng[tid_no]--;
8681 }
8682 } else {
8683 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
8684 scsiq->d3.done_stat = QD_WITH_ERROR;
8685 goto FATAL_ERR_QDONE;
8686 }
8687 if ((scsiq->d2.srb_ptr == 0UL) ||
8688 ((scsiq->q_status & QS_ABORTED) != 0)) {
8689 return (0x11);
8690 } else if (scsiq->q_status == QS_DONE) {
8691 false_overrun = FALSE;
8692 if (scsiq->extra_bytes != 0) {
8693 scsiq->remain_bytes +=
8694 (ADV_DCNT)scsiq->extra_bytes;
8695 }
8696 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
8697 if (scsiq->d3.host_stat ==
8698 QHSTA_M_DATA_OVER_RUN) {
8699 if ((scsiq->
8700 cntl & (QC_DATA_IN | QC_DATA_OUT))
8701 == 0) {
8702 scsiq->d3.done_stat =
8703 QD_NO_ERROR;
8704 scsiq->d3.host_stat =
8705 QHSTA_NO_ERROR;
8706 } else if (false_overrun) {
8707 scsiq->d3.done_stat =
8708 QD_NO_ERROR;
8709 scsiq->d3.host_stat =
8710 QHSTA_NO_ERROR;
8711 }
8712 } else if (scsiq->d3.host_stat ==
8713 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
8714 AscStopChip(iop_base);
8715 AscSetChipControl(iop_base,
8716 (uchar)(CC_SCSI_RESET
8717 | CC_HALT));
8718 DvcDelayNanoSecond(asc_dvc, 60000);
8719 AscSetChipControl(iop_base, CC_HALT);
8720 AscSetChipStatus(iop_base,
8721 CIW_CLR_SCSI_RESET_INT);
8722 AscSetChipStatus(iop_base, 0);
8723 AscSetChipControl(iop_base, 0);
8724 }
8725 }
8726 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04008727 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008728 } else {
8729 if ((AscReadLramByte(iop_base,
8730 (ushort)(q_addr + (ushort)
8731 ASC_SCSIQ_CDB_BEG))
8732 == START_STOP)) {
8733 asc_dvc->unit_not_ready &= ~target_id;
8734 if (scsiq->d3.done_stat != QD_NO_ERROR) {
8735 asc_dvc->start_motor &=
8736 ~target_id;
8737 }
8738 }
8739 }
8740 return (1);
8741 } else {
8742 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
8743 FATAL_ERR_QDONE:
8744 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
Matthew Wilcox895d6b42007-07-26 11:57:06 -04008745 asc_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008746 }
8747 return (0x80);
8748 }
8749 }
8750 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008751}
8752
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008753static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008754{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008755 ASC_CS_TYPE chipstat;
8756 PortAddr iop_base;
8757 ushort saved_ram_addr;
8758 uchar ctrl_reg;
8759 uchar saved_ctrl_reg;
8760 int int_pending;
8761 int status;
8762 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008764 iop_base = asc_dvc->iop_base;
8765 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008766
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008767 if (AscIsIntPending(iop_base) == 0) {
8768 return int_pending;
8769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008770
Matthew Wilcox895d6b42007-07-26 11:57:06 -04008771 if ((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008772 return (ERR);
8773 }
8774 if (asc_dvc->in_critical_cnt != 0) {
8775 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
8776 return (ERR);
8777 }
8778 if (asc_dvc->is_in_int) {
8779 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
8780 return (ERR);
8781 }
8782 asc_dvc->is_in_int = TRUE;
8783 ctrl_reg = AscGetChipControl(iop_base);
8784 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
8785 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
8786 chipstat = AscGetChipStatus(iop_base);
8787 if (chipstat & CSW_SCSI_RESET_LATCH) {
8788 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
8789 int i = 10;
8790 int_pending = TRUE;
8791 asc_dvc->sdtr_done = 0;
8792 saved_ctrl_reg &= (uchar)(~CC_HALT);
8793 while ((AscGetChipStatus(iop_base) &
8794 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
8795 DvcSleepMilliSecond(100);
8796 }
8797 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
8798 AscSetChipControl(iop_base, CC_HALT);
8799 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
8800 AscSetChipStatus(iop_base, 0);
8801 chipstat = AscGetChipStatus(iop_base);
8802 }
8803 }
8804 saved_ram_addr = AscGetChipLramAddr(iop_base);
8805 host_flag = AscReadLramByte(iop_base,
8806 ASCV_HOST_FLAG_B) &
8807 (uchar)(~ASC_HOST_FLAG_IN_ISR);
8808 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
8809 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
8810 if ((chipstat & CSW_INT_PENDING)
8811 || (int_pending)
8812 ) {
8813 AscAckInterrupt(iop_base);
8814 int_pending = TRUE;
8815 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
8816 if (AscIsrChipHalted(asc_dvc) == ERR) {
8817 goto ISR_REPORT_QDONE_FATAL_ERROR;
8818 } else {
8819 saved_ctrl_reg &= (uchar)(~CC_HALT);
8820 }
8821 } else {
8822 ISR_REPORT_QDONE_FATAL_ERROR:
8823 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
8824 while (((status =
8825 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
8826 }
8827 } else {
8828 do {
8829 if ((status =
8830 AscIsrQDone(asc_dvc)) == 1) {
8831 break;
8832 }
8833 } while (status == 0x11);
8834 }
8835 if ((status & 0x80) != 0)
8836 int_pending = ERR;
8837 }
8838 }
8839 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
8840 AscSetChipLramAddr(iop_base, saved_ram_addr);
8841 AscSetChipControl(iop_base, saved_ctrl_reg);
8842 asc_dvc->is_in_int = FALSE;
8843 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008844}
8845
8846/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008847static uchar _asc_mcode_buf[] = {
8848 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8849 0x00, 0x00, 0x00, 0x00,
8850 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
8851 0x00, 0x00, 0x00, 0x00,
8852 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8853 0x00, 0x00, 0x00, 0x00,
8854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8855 0x00, 0x00, 0x00, 0x00,
8856 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
8857 0x00, 0xFF, 0x00, 0x00,
8858 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
8859 0x00, 0x00, 0x00, 0x00,
8860 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
8861 0x00, 0x00, 0x00, 0x00,
8862 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
8863 0x00, 0x00, 0x00, 0x00,
8864 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
8865 0x03, 0x23, 0x36, 0x40,
8866 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
8867 0xC2, 0x00, 0x92, 0x80,
8868 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
8869 0xB6, 0x00, 0x92, 0x80,
8870 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
8871 0x92, 0x80, 0x80, 0x62,
8872 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
8873 0xCD, 0x04, 0x4D, 0x00,
8874 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
8875 0xE6, 0x84, 0xD2, 0xC1,
8876 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
8877 0xC6, 0x81, 0xC2, 0x88,
8878 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
8879 0x84, 0x97, 0x07, 0xA6,
8880 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
8881 0xC2, 0x88, 0xCE, 0x00,
8882 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
8883 0x80, 0x63, 0x07, 0xA6,
8884 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
8885 0x34, 0x01, 0x00, 0x33,
8886 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
8887 0x68, 0x98, 0x4D, 0x04,
8888 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
8889 0xF8, 0x88, 0xFB, 0x23,
8890 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
8891 0x00, 0x33, 0x0A, 0x00,
8892 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
8893 0xC2, 0x88, 0xCD, 0x04,
8894 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
8895 0x06, 0xAB, 0x82, 0x01,
8896 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
8897 0x3C, 0x01, 0x00, 0x05,
8898 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
8899 0x15, 0x23, 0xA1, 0x01,
8900 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
8901 0x06, 0x61, 0x00, 0xA0,
8902 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
8903 0xC2, 0x88, 0x06, 0x23,
8904 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
8905 0x57, 0x60, 0x00, 0xA0,
8906 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
8907 0x4B, 0x00, 0x06, 0x61,
8908 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
8909 0x4F, 0x00, 0x84, 0x97,
8910 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
8911 0x48, 0x04, 0x84, 0x80,
8912 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
8913 0x81, 0x73, 0x06, 0x29,
8914 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
8915 0x04, 0x98, 0xF0, 0x80,
8916 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
8917 0x34, 0x02, 0x03, 0xA6,
8918 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
8919 0x46, 0x82, 0xFE, 0x95,
8920 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
8921 0x07, 0xA6, 0x5A, 0x02,
8922 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
8923 0x48, 0x82, 0x60, 0x96,
8924 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
8925 0x04, 0x01, 0x0C, 0xDC,
8926 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
8927 0x6F, 0x00, 0xA5, 0x01,
8928 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
8929 0x02, 0xA6, 0xAA, 0x02,
8930 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
8931 0x01, 0xA6, 0xB4, 0x02,
8932 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
8933 0x80, 0x63, 0x00, 0x43,
8934 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
8935 0x04, 0x61, 0x84, 0x01,
8936 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
8937 0x00, 0x00, 0xEA, 0x82,
8938 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
8939 0x00, 0x33, 0x1F, 0x00,
8940 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
8941 0xB6, 0x2D, 0x01, 0xA6,
8942 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
8943 0x10, 0x03, 0x03, 0xA6,
8944 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
8945 0x7C, 0x95, 0xEE, 0x82,
8946 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
8947 0x04, 0x01, 0x2D, 0xC8,
8948 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
8949 0x05, 0x05, 0x86, 0x98,
8950 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
8951 0x3C, 0x04, 0x06, 0xA6,
8952 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
8953 0x7C, 0x95, 0x32, 0x83,
8954 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
8955 0xEB, 0x04, 0x00, 0x33,
8956 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
8957 0xFF, 0xA2, 0x7A, 0x03,
8958 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
8959 0x00, 0xA2, 0x9A, 0x03,
8960 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
8961 0x01, 0xA6, 0x96, 0x03,
8962 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
8963 0xA4, 0x03, 0x00, 0xA6,
8964 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
8965 0x07, 0xA6, 0xB2, 0x03,
8966 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
8967 0xA8, 0x98, 0x80, 0x42,
8968 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
8969 0xC0, 0x83, 0x00, 0x33,
8970 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
8971 0xA0, 0x01, 0x12, 0x23,
8972 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
8973 0x80, 0x67, 0x05, 0x23,
8974 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
8975 0x06, 0xA6, 0x0A, 0x04,
8976 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
8977 0xF4, 0x83, 0x20, 0x84,
8978 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
8979 0x83, 0x03, 0x80, 0x63,
8980 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
8981 0x38, 0x04, 0x00, 0x33,
8982 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
8983 0x1D, 0x01, 0x06, 0xCC,
8984 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
8985 0xA2, 0x0D, 0x80, 0x63,
8986 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
8987 0x80, 0x63, 0xA3, 0x01,
8988 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
8989 0x76, 0x04, 0xE0, 0x00,
8990 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
8991 0x00, 0x33, 0x1E, 0x00,
8992 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
8993 0x08, 0x23, 0x22, 0xA3,
8994 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
8995 0xC4, 0x04, 0x42, 0x23,
8996 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
8997 0xF8, 0x88, 0x04, 0x98,
8998 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
8999 0x81, 0x62, 0xE8, 0x81,
9000 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
9001 0x00, 0x33, 0x00, 0x81,
9002 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
9003 0xF8, 0x88, 0x04, 0x23,
9004 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
9005 0xF4, 0x04, 0x00, 0x33,
9006 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9007 0x04, 0x23, 0xA0, 0x01,
9008 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9009 0x00, 0xA3, 0x22, 0x05,
9010 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9011 0x46, 0x97, 0xCD, 0x04,
9012 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9013 0x82, 0x01, 0x34, 0x85,
9014 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9015 0x1D, 0x01, 0x04, 0xD6,
9016 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9017 0x49, 0x00, 0x81, 0x01,
9018 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9019 0x49, 0x04, 0x80, 0x01,
9020 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9021 0x01, 0x23, 0xEA, 0x00,
9022 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9023 0x07, 0xA4, 0xF8, 0x05,
9024 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9025 0xC2, 0x88, 0x04, 0xA0,
9026 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9027 0x00, 0xA2, 0xA4, 0x05,
9028 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9029 0x62, 0x97, 0x04, 0x85,
9030 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9031 0xF4, 0x85, 0x03, 0xA0,
9032 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9033 0xCC, 0x86, 0x07, 0xA0,
9034 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9035 0x80, 0x67, 0x80, 0x63,
9036 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9037 0xF8, 0x88, 0x07, 0x23,
9038 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9039 0x00, 0x63, 0x4A, 0x00,
9040 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9041 0x07, 0x41, 0x83, 0x03,
9042 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9043 0x1D, 0x01, 0x01, 0xD6,
9044 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9045 0x07, 0xA6, 0x7C, 0x05,
9046 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9047 0x52, 0x00, 0x06, 0x61,
9048 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9049 0x00, 0x63, 0x1D, 0x01,
9050 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9051 0x07, 0x41, 0x00, 0x63,
9052 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9053 0xDF, 0x00, 0x06, 0xA6,
9054 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9055 0x00, 0x40, 0xC0, 0x20,
9056 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9057 0x06, 0xA6, 0x94, 0x06,
9058 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9059 0x40, 0x0E, 0x80, 0x63,
9060 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9061 0x80, 0x63, 0x00, 0x43,
9062 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9063 0x80, 0x67, 0x40, 0x0E,
9064 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9065 0x07, 0xA6, 0xD6, 0x06,
9066 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9067 0x0A, 0x2B, 0x07, 0xA6,
9068 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9069 0xF4, 0x06, 0xC0, 0x0E,
9070 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9071 0x81, 0x62, 0x04, 0x01,
9072 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9073 0x8C, 0x06, 0x00, 0x33,
9074 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9075 0x80, 0x63, 0x06, 0xA6,
9076 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9077 0x00, 0x00, 0x80, 0x67,
9078 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9079 0xBF, 0x23, 0x04, 0x61,
9080 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9081 0x00, 0x01, 0xF2, 0x00,
9082 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9083 0x80, 0x05, 0x81, 0x05,
9084 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9085 0x70, 0x00, 0x81, 0x01,
9086 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9087 0x70, 0x00, 0x80, 0x01,
9088 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9089 0xF1, 0x00, 0x70, 0x00,
9090 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9091 0x71, 0x04, 0x70, 0x00,
9092 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9093 0xA3, 0x01, 0xA2, 0x01,
9094 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9095 0xC4, 0x07, 0x00, 0x33,
9096 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9097 0x48, 0x00, 0xB0, 0x01,
9098 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9099 0x00, 0xA2, 0xE4, 0x07,
9100 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9101 0x05, 0x05, 0x00, 0x63,
9102 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9103 0x76, 0x08, 0x80, 0x02,
9104 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9105 0x00, 0x02, 0x00, 0xA0,
9106 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9107 0x00, 0x63, 0xF3, 0x04,
9108 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9109 0x00, 0xA2, 0x44, 0x08,
9110 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9111 0x24, 0x08, 0x04, 0x98,
9112 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9113 0x5A, 0x88, 0x02, 0x01,
9114 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9115 0x00, 0xA3, 0x64, 0x08,
9116 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9117 0x06, 0xA6, 0x76, 0x08,
9118 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9119 0x00, 0x63, 0x38, 0x2B,
9120 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9121 0x05, 0x05, 0xB2, 0x09,
9122 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9123 0x80, 0x32, 0x80, 0x36,
9124 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9125 0x40, 0x36, 0x40, 0x3A,
9126 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9127 0x5D, 0x00, 0xFE, 0xC3,
9128 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9129 0xFF, 0xFD, 0x80, 0x73,
9130 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9131 0xA1, 0x23, 0xA1, 0x01,
9132 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9133 0x80, 0x00, 0x03, 0xC2,
9134 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9135 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009136};
9137
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009138static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9139static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009140
9141#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009142static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9143 INQUIRY,
9144 REQUEST_SENSE,
9145 READ_CAPACITY,
9146 READ_TOC,
9147 MODE_SELECT,
9148 MODE_SENSE,
9149 MODE_SELECT_10,
9150 MODE_SENSE_10,
9151 0xFF,
9152 0xFF,
9153 0xFF,
9154 0xFF,
9155 0xFF,
9156 0xFF,
9157 0xFF,
9158 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009159};
9160
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009161static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009162{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009163 PortAddr iop_base;
9164 ulong last_int_level;
9165 int sta;
9166 int n_q_required;
9167 int disable_syn_offset_one_fix;
9168 int i;
9169 ASC_PADDR addr;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009170 ushort sg_entry_cnt = 0;
9171 ushort sg_entry_cnt_minus_one = 0;
9172 uchar target_ix;
9173 uchar tid_no;
9174 uchar sdtr_data;
9175 uchar extra_bytes;
9176 uchar scsi_cmd;
9177 uchar disable_cmd;
9178 ASC_SG_HEAD *sg_head;
9179 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009180
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009181 iop_base = asc_dvc->iop_base;
9182 sg_head = scsiq->sg_head;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009183 if (asc_dvc->err_code != 0)
9184 return (ERR);
9185 if (scsiq == (ASC_SCSI_Q *)0L) {
9186 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9187 return (ERR);
9188 }
9189 scsiq->q1.q_no = 0;
9190 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9191 scsiq->q1.extra_bytes = 0;
9192 }
9193 sta = 0;
9194 target_ix = scsiq->q2.target_ix;
9195 tid_no = ASC_TIX_TO_TID(target_ix);
9196 n_q_required = 1;
9197 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9198 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9199 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9200 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9201 AscMsgOutSDTR(asc_dvc,
9202 asc_dvc->
9203 sdtr_period_tbl[(sdtr_data >> 4) &
9204 (uchar)(asc_dvc->
9205 max_sdtr_index -
9206 1)],
9207 (uchar)(sdtr_data & (uchar)
9208 ASC_SYN_MAX_OFFSET));
9209 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9210 }
9211 }
9212 last_int_level = DvcEnterCritical();
9213 if (asc_dvc->in_critical_cnt != 0) {
9214 DvcLeaveCritical(last_int_level);
9215 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9216 return (ERR);
9217 }
9218 asc_dvc->in_critical_cnt++;
9219 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9220 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9221 asc_dvc->in_critical_cnt--;
9222 DvcLeaveCritical(last_int_level);
9223 return (ERR);
9224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009225#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009226 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9227 asc_dvc->in_critical_cnt--;
9228 DvcLeaveCritical(last_int_level);
9229 return (ERR);
9230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009231#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009232 if (sg_entry_cnt == 1) {
9233 scsiq->q1.data_addr =
9234 (ADV_PADDR)sg_head->sg_list[0].addr;
9235 scsiq->q1.data_cnt =
9236 (ADV_DCNT)sg_head->sg_list[0].bytes;
9237 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9238 }
9239 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9240 }
9241 scsi_cmd = scsiq->cdbptr[0];
9242 disable_syn_offset_one_fix = FALSE;
9243 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9244 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9245 if (scsiq->q1.cntl & QC_SG_HEAD) {
9246 data_cnt = 0;
9247 for (i = 0; i < sg_entry_cnt; i++) {
9248 data_cnt +=
9249 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9250 bytes);
9251 }
9252 } else {
9253 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9254 }
9255 if (data_cnt != 0UL) {
9256 if (data_cnt < 512UL) {
9257 disable_syn_offset_one_fix = TRUE;
9258 } else {
9259 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9260 i++) {
9261 disable_cmd =
9262 _syn_offset_one_disable_cmd[i];
9263 if (disable_cmd == 0xFF) {
9264 break;
9265 }
9266 if (scsi_cmd == disable_cmd) {
9267 disable_syn_offset_one_fix =
9268 TRUE;
9269 break;
9270 }
9271 }
9272 }
9273 }
9274 }
9275 if (disable_syn_offset_one_fix) {
9276 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9277 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9278 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9279 } else {
9280 scsiq->q2.tag_code &= 0x27;
9281 }
9282 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9283 if (asc_dvc->bug_fix_cntl) {
9284 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9285 if ((scsi_cmd == READ_6) ||
9286 (scsi_cmd == READ_10)) {
9287 addr =
9288 (ADV_PADDR)le32_to_cpu(sg_head->
9289 sg_list
9290 [sg_entry_cnt_minus_one].
9291 addr) +
9292 (ADV_DCNT)le32_to_cpu(sg_head->
9293 sg_list
9294 [sg_entry_cnt_minus_one].
9295 bytes);
9296 extra_bytes =
9297 (uchar)((ushort)addr & 0x0003);
9298 if ((extra_bytes != 0)
9299 &&
9300 ((scsiq->q2.
9301 tag_code &
9302 ASC_TAG_FLAG_EXTRA_BYTES)
9303 == 0)) {
9304 scsiq->q2.tag_code |=
9305 ASC_TAG_FLAG_EXTRA_BYTES;
9306 scsiq->q1.extra_bytes =
9307 extra_bytes;
9308 data_cnt =
9309 le32_to_cpu(sg_head->
9310 sg_list
9311 [sg_entry_cnt_minus_one].
9312 bytes);
9313 data_cnt -=
9314 (ASC_DCNT) extra_bytes;
9315 sg_head->
9316 sg_list
9317 [sg_entry_cnt_minus_one].
9318 bytes =
9319 cpu_to_le32(data_cnt);
9320 }
9321 }
9322 }
9323 }
9324 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009325#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009326 /*
9327 * Set the sg_entry_cnt to the maximum possible. The rest of
9328 * the SG elements will be copied when the RISC completes the
9329 * SG elements that fit and halts.
9330 */
9331 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9332 sg_entry_cnt = ASC_MAX_SG_LIST;
9333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009334#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009335 n_q_required = AscSgListToQueue(sg_entry_cnt);
9336 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9337 (uint) n_q_required)
9338 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9339 if ((sta =
9340 AscSendScsiQueue(asc_dvc, scsiq,
9341 n_q_required)) == 1) {
9342 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009343 DvcLeaveCritical(last_int_level);
9344 return (sta);
9345 }
9346 }
9347 } else {
9348 if (asc_dvc->bug_fix_cntl) {
9349 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9350 if ((scsi_cmd == READ_6) ||
9351 (scsi_cmd == READ_10)) {
9352 addr =
9353 le32_to_cpu(scsiq->q1.data_addr) +
9354 le32_to_cpu(scsiq->q1.data_cnt);
9355 extra_bytes =
9356 (uchar)((ushort)addr & 0x0003);
9357 if ((extra_bytes != 0)
9358 &&
9359 ((scsiq->q2.
9360 tag_code &
9361 ASC_TAG_FLAG_EXTRA_BYTES)
9362 == 0)) {
9363 data_cnt =
9364 le32_to_cpu(scsiq->q1.
9365 data_cnt);
9366 if (((ushort)data_cnt & 0x01FF)
9367 == 0) {
9368 scsiq->q2.tag_code |=
9369 ASC_TAG_FLAG_EXTRA_BYTES;
9370 data_cnt -= (ASC_DCNT)
9371 extra_bytes;
9372 scsiq->q1.data_cnt =
9373 cpu_to_le32
9374 (data_cnt);
9375 scsiq->q1.extra_bytes =
9376 extra_bytes;
9377 }
9378 }
9379 }
9380 }
9381 }
9382 n_q_required = 1;
9383 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9384 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9385 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9386 n_q_required)) == 1) {
9387 asc_dvc->in_critical_cnt--;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009388 DvcLeaveCritical(last_int_level);
9389 return (sta);
9390 }
9391 }
9392 }
9393 asc_dvc->in_critical_cnt--;
9394 DvcLeaveCritical(last_int_level);
9395 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009396}
9397
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009398static int
9399AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009400{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009401 PortAddr iop_base;
9402 uchar free_q_head;
9403 uchar next_qp;
9404 uchar tid_no;
9405 uchar target_ix;
9406 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009408 iop_base = asc_dvc->iop_base;
9409 target_ix = scsiq->q2.target_ix;
9410 tid_no = ASC_TIX_TO_TID(target_ix);
9411 sta = 0;
9412 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9413 if (n_q_required > 1) {
9414 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9415 free_q_head, (uchar)
9416 (n_q_required)))
9417 != (uchar)ASC_QLINK_END) {
9418 asc_dvc->last_q_shortage = 0;
9419 scsiq->sg_head->queue_cnt = n_q_required - 1;
9420 scsiq->q1.q_no = free_q_head;
9421 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9422 free_q_head)) == 1) {
9423 AscPutVarFreeQHead(iop_base, next_qp);
9424 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9425 asc_dvc->cur_dvc_qng[tid_no]++;
9426 }
9427 return (sta);
9428 }
9429 } else if (n_q_required == 1) {
9430 if ((next_qp = AscAllocFreeQueue(iop_base,
9431 free_q_head)) !=
9432 ASC_QLINK_END) {
9433 scsiq->q1.q_no = free_q_head;
9434 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9435 free_q_head)) == 1) {
9436 AscPutVarFreeQHead(iop_base, next_qp);
9437 asc_dvc->cur_total_qng++;
9438 asc_dvc->cur_dvc_qng[tid_no]++;
9439 }
9440 return (sta);
9441 }
9442 }
9443 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009444}
9445
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009446static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009447{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009448 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009450 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9451 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9452 n_sg_list_qs++;
9453 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009454}
9455
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009456static uint
9457AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009458{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009459 uint cur_used_qs;
9460 uint cur_free_qs;
9461 ASC_SCSI_BIT_ID_TYPE target_id;
9462 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009463
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009464 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9465 tid_no = ASC_TIX_TO_TID(target_ix);
9466 if ((asc_dvc->unit_not_ready & target_id) ||
9467 (asc_dvc->queue_full_or_busy & target_id)) {
9468 return (0);
9469 }
9470 if (n_qs == 1) {
9471 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9472 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9473 } else {
9474 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9475 (uint) ASC_MIN_FREE_Q;
9476 }
9477 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9478 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9479 if (asc_dvc->cur_dvc_qng[tid_no] >=
9480 asc_dvc->max_dvc_qng[tid_no]) {
9481 return (0);
9482 }
9483 return (cur_free_qs);
9484 }
9485 if (n_qs > 1) {
9486 if ((n_qs > asc_dvc->last_q_shortage)
9487 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9488 asc_dvc->last_q_shortage = n_qs;
9489 }
9490 }
9491 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009492}
9493
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009494static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009495{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009496 ushort q_addr;
9497 uchar tid_no;
9498 uchar sdtr_data;
9499 uchar syn_period_ix;
9500 uchar syn_offset;
9501 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009502
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009503 iop_base = asc_dvc->iop_base;
9504 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9505 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9506 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9507 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9508 syn_period_ix =
9509 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9510 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9511 AscMsgOutSDTR(asc_dvc,
9512 asc_dvc->sdtr_period_tbl[syn_period_ix],
9513 syn_offset);
9514 scsiq->q1.cntl |= QC_MSG_OUT;
9515 }
9516 q_addr = ASC_QNO_TO_QADDR(q_no);
9517 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9518 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9519 }
9520 scsiq->q1.status = QS_FREE;
9521 AscMemWordCopyPtrToLram(iop_base,
9522 q_addr + ASC_SCSIQ_CDB_BEG,
9523 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009524
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009525 DvcPutScsiQ(iop_base,
9526 q_addr + ASC_SCSIQ_CPY_BEG,
9527 (uchar *)&scsiq->q1.cntl,
9528 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9529 AscWriteLramWord(iop_base,
9530 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9531 (ushort)(((ushort)scsiq->q1.
9532 q_no << 8) | (ushort)QS_READY));
9533 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009534}
9535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009536static int
9537AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009538{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009539 int sta;
9540 int i;
9541 ASC_SG_HEAD *sg_head;
9542 ASC_SG_LIST_Q scsi_sg_q;
9543 ASC_DCNT saved_data_addr;
9544 ASC_DCNT saved_data_cnt;
9545 PortAddr iop_base;
9546 ushort sg_list_dwords;
9547 ushort sg_index;
9548 ushort sg_entry_cnt;
9549 ushort q_addr;
9550 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009551
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009552 iop_base = asc_dvc->iop_base;
9553 sg_head = scsiq->sg_head;
9554 saved_data_addr = scsiq->q1.data_addr;
9555 saved_data_cnt = scsiq->q1.data_cnt;
9556 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9557 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009558#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009559 /*
9560 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9561 * then not all SG elements will fit in the allocated queues.
9562 * The rest of the SG elements will be copied when the RISC
9563 * completes the SG elements that fit and halts.
9564 */
9565 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9566 /*
9567 * Set sg_entry_cnt to be the number of SG elements that
9568 * will fit in the allocated SG queues. It is minus 1, because
9569 * the first SG element is handled above. ASC_MAX_SG_LIST is
9570 * already inflated by 1 to account for this. For example it
9571 * may be 50 which is 1 + 7 queues * 7 SG elements.
9572 */
9573 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009574
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009575 /*
9576 * Keep track of remaining number of SG elements that will
9577 * need to be handled from a_isr.c.
9578 */
9579 scsiq->remain_sg_entry_cnt =
9580 sg_head->entry_cnt - ASC_MAX_SG_LIST;
9581 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009582#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009583 /*
9584 * Set sg_entry_cnt to be the number of SG elements that
9585 * will fit in the allocated SG queues. It is minus 1, because
9586 * the first SG element is handled above.
9587 */
9588 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009589#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009591#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009592 if (sg_entry_cnt != 0) {
9593 scsiq->q1.cntl |= QC_SG_HEAD;
9594 q_addr = ASC_QNO_TO_QADDR(q_no);
9595 sg_index = 1;
9596 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
9597 scsi_sg_q.sg_head_qp = q_no;
9598 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
9599 for (i = 0; i < sg_head->queue_cnt; i++) {
9600 scsi_sg_q.seq_no = i + 1;
9601 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
9602 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
9603 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
9604 if (i == 0) {
9605 scsi_sg_q.sg_list_cnt =
9606 ASC_SG_LIST_PER_Q;
9607 scsi_sg_q.sg_cur_list_cnt =
9608 ASC_SG_LIST_PER_Q;
9609 } else {
9610 scsi_sg_q.sg_list_cnt =
9611 ASC_SG_LIST_PER_Q - 1;
9612 scsi_sg_q.sg_cur_list_cnt =
9613 ASC_SG_LIST_PER_Q - 1;
9614 }
9615 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009616#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009617 /*
9618 * This is the last SG queue in the list of
9619 * allocated SG queues. If there are more
9620 * SG elements than will fit in the allocated
9621 * queues, then set the QCSG_SG_XFER_MORE flag.
9622 */
9623 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9624 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
9625 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009626#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009627 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009628#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009629 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009630#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009631 sg_list_dwords = sg_entry_cnt << 1;
9632 if (i == 0) {
9633 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
9634 scsi_sg_q.sg_cur_list_cnt =
9635 sg_entry_cnt;
9636 } else {
9637 scsi_sg_q.sg_list_cnt =
9638 sg_entry_cnt - 1;
9639 scsi_sg_q.sg_cur_list_cnt =
9640 sg_entry_cnt - 1;
9641 }
9642 sg_entry_cnt = 0;
9643 }
9644 next_qp = AscReadLramByte(iop_base,
9645 (ushort)(q_addr +
9646 ASC_SCSIQ_B_FWD));
9647 scsi_sg_q.q_no = next_qp;
9648 q_addr = ASC_QNO_TO_QADDR(next_qp);
9649 AscMemWordCopyPtrToLram(iop_base,
9650 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
9651 (uchar *)&scsi_sg_q,
9652 sizeof(ASC_SG_LIST_Q) >> 1);
9653 AscMemDWordCopyPtrToLram(iop_base,
9654 q_addr + ASC_SGQ_LIST_BEG,
9655 (uchar *)&sg_head->
9656 sg_list[sg_index],
9657 sg_list_dwords);
9658 sg_index += ASC_SG_LIST_PER_Q;
9659 scsiq->next_sg_index = sg_index;
9660 }
9661 } else {
9662 scsiq->q1.cntl &= ~QC_SG_HEAD;
9663 }
9664 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
9665 scsiq->q1.data_addr = saved_data_addr;
9666 scsiq->q1.data_cnt = saved_data_cnt;
9667 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009668}
9669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009670static int
9671AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009672{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009673 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009675 if (AscHostReqRiscHalt(iop_base)) {
9676 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9677 AscStartChip(iop_base);
9678 return (sta);
9679 }
9680 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009681}
9682
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009683static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009684{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009685 ASC_SCSI_BIT_ID_TYPE org_id;
9686 int i;
9687 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009688
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009689 AscSetBank(iop_base, 1);
9690 org_id = AscReadChipDvcID(iop_base);
9691 for (i = 0; i <= ASC_MAX_TID; i++) {
9692 if (org_id == (0x01 << i))
9693 break;
9694 }
9695 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
9696 AscWriteChipDvcID(iop_base, id);
9697 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
9698 AscSetBank(iop_base, 0);
9699 AscSetChipSyn(iop_base, sdtr_data);
9700 if (AscGetChipSyn(iop_base) != sdtr_data) {
9701 sta = FALSE;
9702 }
9703 } else {
9704 sta = FALSE;
9705 }
9706 AscSetBank(iop_base, 1);
9707 AscWriteChipDvcID(iop_base, org_id);
9708 AscSetBank(iop_base, 0);
9709 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009710}
9711
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009712static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009713{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009714 uchar i;
9715 ushort s_addr;
9716 PortAddr iop_base;
9717 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009718
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009719 iop_base = asc_dvc->iop_base;
9720 warn_code = 0;
9721 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
9722 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
9723 64) >> 1)
9724 );
9725 i = ASC_MIN_ACTIVE_QNO;
9726 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
9727 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9728 (uchar)(i + 1));
9729 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9730 (uchar)(asc_dvc->max_total_qng));
9731 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9732 (uchar)i);
9733 i++;
9734 s_addr += ASC_QBLK_SIZE;
9735 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
9736 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9737 (uchar)(i + 1));
9738 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9739 (uchar)(i - 1));
9740 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9741 (uchar)i);
9742 }
9743 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9744 (uchar)ASC_QLINK_END);
9745 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9746 (uchar)(asc_dvc->max_total_qng - 1));
9747 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9748 (uchar)asc_dvc->max_total_qng);
9749 i++;
9750 s_addr += ASC_QBLK_SIZE;
9751 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
9752 i++, s_addr += ASC_QBLK_SIZE) {
9753 AscWriteLramByte(iop_base,
9754 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
9755 AscWriteLramByte(iop_base,
9756 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
9757 AscWriteLramByte(iop_base,
9758 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
9759 }
9760 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009761}
9762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009763static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009764{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009765 PortAddr iop_base;
9766 int i;
9767 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009769 iop_base = asc_dvc->iop_base;
9770 AscPutRiscVarFreeQHead(iop_base, 1);
9771 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9772 AscPutVarFreeQHead(iop_base, 1);
9773 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9774 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
9775 (uchar)((int)asc_dvc->max_total_qng + 1));
9776 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
9777 (uchar)((int)asc_dvc->max_total_qng + 2));
9778 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
9779 asc_dvc->max_total_qng);
9780 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
9781 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
9782 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
9783 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
9784 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
9785 AscPutQDoneInProgress(iop_base, 0);
9786 lram_addr = ASC_QADR_BEG;
9787 for (i = 0; i < 32; i++, lram_addr += 2) {
9788 AscWriteLramWord(iop_base, lram_addr, 0);
9789 }
9790 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009791}
9792
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009793static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009794{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009795 if (asc_dvc->err_code == 0) {
9796 asc_dvc->err_code = err_code;
9797 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
9798 err_code);
9799 }
9800 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009801}
9802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009803static uchar
9804AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009805{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009806 EXT_MSG sdtr_buf;
9807 uchar sdtr_period_index;
9808 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009810 iop_base = asc_dvc->iop_base;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009811 sdtr_buf.msg_type = EXTENDED_MESSAGE;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009812 sdtr_buf.msg_len = MS_SDTR_LEN;
Matthew Wilcox47d853c2007-07-26 11:41:33 -04009813 sdtr_buf.msg_req = EXTENDED_SDTR;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009814 sdtr_buf.xfer_period = sdtr_period;
9815 sdtr_offset &= ASC_SYN_MAX_OFFSET;
9816 sdtr_buf.req_ack_offset = sdtr_offset;
9817 if ((sdtr_period_index =
9818 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
9819 asc_dvc->max_sdtr_index) {
9820 AscMemWordCopyPtrToLram(iop_base,
9821 ASCV_MSGOUT_BEG,
9822 (uchar *)&sdtr_buf,
9823 sizeof(EXT_MSG) >> 1);
9824 return ((sdtr_period_index << 4) | sdtr_offset);
9825 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009826
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009827 sdtr_buf.req_ack_offset = 0;
9828 AscMemWordCopyPtrToLram(iop_base,
9829 ASCV_MSGOUT_BEG,
9830 (uchar *)&sdtr_buf,
9831 sizeof(EXT_MSG) >> 1);
9832 return (0);
9833 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009834}
9835
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009836static uchar
9837AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009838{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009839 uchar byte;
9840 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009841
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009842 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
9843 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
9844 ) {
9845 return (0xFF);
9846 }
9847 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
9848 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009849}
9850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009851static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009852{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009853 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9854 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
9855 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009856}
9857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009858static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009859{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009860 uchar *period_table;
9861 int max_index;
9862 int min_index;
9863 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009864
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009865 period_table = asc_dvc->sdtr_period_tbl;
9866 max_index = (int)asc_dvc->max_sdtr_index;
9867 min_index = (int)asc_dvc->host_init_sdtr_index;
9868 if ((syn_time <= period_table[max_index])) {
9869 for (i = min_index; i < (max_index - 1); i++) {
9870 if (syn_time <= period_table[i]) {
9871 return ((uchar)i);
9872 }
9873 }
9874 return ((uchar)max_index);
9875 } else {
9876 return ((uchar)(max_index + 1));
9877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009878}
9879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009880static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009881{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009882 ushort q_addr;
9883 uchar next_qp;
9884 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009885
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009886 q_addr = ASC_QNO_TO_QADDR(free_q_head);
9887 q_status = (uchar)AscReadLramByte(iop_base,
9888 (ushort)(q_addr +
9889 ASC_SCSIQ_B_STATUS));
9890 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
9891 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
9892 return (next_qp);
9893 }
9894 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009895}
9896
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009897static uchar
9898AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009899{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009900 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009901
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009902 for (i = 0; i < n_free_q; i++) {
9903 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
9904 == ASC_QLINK_END) {
9905 return (ASC_QLINK_END);
9906 }
9907 }
9908 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009909}
9910
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009911static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009912{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009913 int count = 0;
9914 int sta = 0;
9915 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009916
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009917 if (AscIsChipHalted(iop_base))
9918 return (1);
9919 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
9920 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9921 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
9922 do {
9923 if (AscIsChipHalted(iop_base)) {
9924 sta = 1;
9925 break;
9926 }
9927 DvcSleepMilliSecond(100);
9928 } while (count++ < 20);
9929 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
9930 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009931}
9932
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009933static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009934{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009935 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009936
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009937 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
9938 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
9939 ASC_STOP_REQ_RISC_STOP);
9940 do {
9941 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
9942 ASC_STOP_ACK_RISC_STOP) {
9943 return (1);
9944 }
9945 DvcSleepMilliSecond(100);
9946 } while (count++ < 20);
9947 }
9948 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009949}
9950
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009951static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009952{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009953 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009954}
9955
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009956static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009957{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009958 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009959}
9960
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009961static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009962{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009963 AscSetChipControl(iop_base, 0);
9964 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
9965 return (0);
9966 }
9967 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009968}
9969
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009970static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009971{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009972 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009973
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009974 cc_val =
9975 AscGetChipControl(iop_base) &
9976 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
9977 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
9978 AscSetChipIH(iop_base, INS_HALT);
9979 AscSetChipIH(iop_base, INS_RFLAG_WTM);
9980 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
9981 return (0);
9982 }
9983 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009984}
9985
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009986static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009987{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009988 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
9989 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
9990 return (1);
9991 }
9992 }
9993 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009994}
9995
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009996static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009997{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009998 AscSetBank(iop_base, 1);
9999 AscWriteChipIH(iop_base, ins_code);
10000 AscSetBank(iop_base, 0);
10001 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010002}
10003
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010004static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010005{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010006 uchar host_flag;
10007 uchar risc_flag;
10008 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010009
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010010 loop = 0;
10011 do {
10012 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10013 if (loop++ > 0x7FFF) {
10014 break;
10015 }
10016 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10017 host_flag =
10018 AscReadLramByte(iop_base,
10019 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10020 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10021 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10022 AscSetChipStatus(iop_base, CIW_INT_ACK);
10023 loop = 0;
10024 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10025 AscSetChipStatus(iop_base, CIW_INT_ACK);
10026 if (loop++ > 3) {
10027 break;
10028 }
10029 }
10030 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10031 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010032}
10033
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010034static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010035{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010036 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010037
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010038 cfg = AscGetChipCfgLsw(iop_base);
10039 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10040 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010041}
10042
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010043static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010044{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010045 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010046
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010047 cfg = AscGetChipCfgLsw(iop_base);
10048 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10049 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010050}
10051
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010052static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010053{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010054 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010055
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010056 val = AscGetChipControl(iop_base) &
10057 (~
10058 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10059 CC_CHIP_RESET));
10060 if (bank == 1) {
10061 val |= CC_BANK_ONE;
10062 } else if (bank == 2) {
10063 val |= CC_DIAG | CC_BANK_ONE;
10064 } else {
10065 val &= ~CC_BANK_ONE;
10066 }
10067 AscSetChipControl(iop_base, val);
10068 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010069}
10070
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010071static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010072{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010073 PortAddr iop_base;
10074 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010075
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010076 iop_base = asc_dvc->iop_base;
10077 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10078 && (i-- > 0)) {
10079 DvcSleepMilliSecond(100);
10080 }
10081 AscStopChip(iop_base);
10082 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10083 DvcDelayNanoSecond(asc_dvc, 60000);
10084 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10085 AscSetChipIH(iop_base, INS_HALT);
10086 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10087 AscSetChipControl(iop_base, CC_HALT);
10088 DvcSleepMilliSecond(200);
10089 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10090 AscSetChipStatus(iop_base, 0);
10091 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010092}
10093
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010094static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010095{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010096 if (bus_type & ASC_IS_ISA)
10097 return (ASC_MAX_ISA_DMA_COUNT);
10098 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10099 return (ASC_MAX_VL_DMA_COUNT);
10100 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010101}
10102
10103#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010104static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010105{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010106 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010107
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010108 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10109 if (channel == 0x03)
10110 return (0);
10111 else if (channel == 0x00)
10112 return (7);
10113 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010114}
10115
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010116static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010117{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010118 ushort cfg_lsw;
10119 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010120
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010121 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10122 if (dma_channel == 7)
10123 value = 0x00;
10124 else
10125 value = dma_channel - 4;
10126 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10127 cfg_lsw |= value;
10128 AscSetChipCfgLsw(iop_base, cfg_lsw);
10129 return (AscGetIsaDmaChannel(iop_base));
10130 }
10131 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010132}
10133
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010134static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010135{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010136 speed_value &= 0x07;
10137 AscSetBank(iop_base, 1);
10138 AscWriteChipDmaSpeed(iop_base, speed_value);
10139 AscSetBank(iop_base, 0);
10140 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010141}
10142
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010143static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010144{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010145 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010146
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010147 AscSetBank(iop_base, 1);
10148 speed_value = AscReadChipDmaSpeed(iop_base);
10149 speed_value &= 0x07;
10150 AscSetBank(iop_base, 0);
10151 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010152}
10153#endif /* CONFIG_ISA */
10154
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010155static ushort __devinit AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010156{
Matthew Wilcox9649af32007-07-26 21:51:47 -060010157 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010158
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010159 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -060010160 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010161 return (UW_ERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010162
Matthew Wilcox9649af32007-07-26 21:51:47 -060010163 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010164 warn_code |= AscInitAscDvcVar(asc_dvc);
10165 warn_code |= AscInitFromEEP(asc_dvc);
10166 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010167 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010168 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010169 } else {
10170 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10171 }
Matthew Wilcoxecec1942007-07-30 08:08:22 -060010172 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010173}
10174
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010175static unsigned short __devinit
10176AscInitSetConfig(struct pci_dev *pdev, ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010177{
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010178 PortAddr iop_base = asc_dvc->iop_base;
10179 unsigned short cfg_msw;
10180 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010181
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010182 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10183 if (asc_dvc->err_code != 0)
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010184 return UW_ERR;
10185 if (!AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010186 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010187 return 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010189
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010190 cfg_msw = AscGetChipCfgMsw(iop_base);
10191 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10192 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10193 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10194 AscSetChipCfgMsw(iop_base, cfg_msw);
10195 }
10196 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10197 asc_dvc->cfg->cmd_qng_enabled) {
10198 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10199 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10200 }
10201 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10202 warn_code |= ASC_WARN_AUTO_CONFIG;
10203 }
10204 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10205 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10206 != asc_dvc->irq_no) {
10207 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10208 }
10209 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010210#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010211 if (asc_dvc->bus_type & ASC_IS_PCI) {
10212 cfg_msw &= 0xFFC0;
10213 AscSetChipCfgMsw(iop_base, cfg_msw);
10214 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10215 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010216 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
10217 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010218 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10219 asc_dvc->bug_fix_cntl |=
10220 ASC_BUG_FIX_ASYN_USE_SYN;
10221 }
10222 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010223 } else
10224#endif /* CONFIG_PCI */
10225 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010226 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10227 == ASC_CHIP_VER_ASYN_BUG) {
10228 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10229 }
10230 }
10231 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10232 asc_dvc->cfg->chip_scsi_id) {
10233 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10234 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010235#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010236 if (asc_dvc->bus_type & ASC_IS_ISA) {
10237 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10238 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010240#endif /* CONFIG_ISA */
Matthew Wilcox394dbf32007-07-26 11:56:40 -040010241
10242 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10243 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010244}
10245
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010246static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010247{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010248 ushort warn_code;
10249 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010250
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010251 iop_base = asc_dvc->iop_base;
10252 warn_code = 0;
10253 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10254 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10255 AscResetChipAndScsiBus(asc_dvc);
10256 DvcSleepMilliSecond((ASC_DCNT)
10257 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10258 }
10259 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10260 if (asc_dvc->err_code != 0)
10261 return (UW_ERR);
10262 if (!AscFindSignature(asc_dvc->iop_base)) {
10263 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10264 return (warn_code);
10265 }
10266 AscDisableInterrupt(iop_base);
10267 warn_code |= AscInitLram(asc_dvc);
10268 if (asc_dvc->err_code != 0)
10269 return (UW_ERR);
10270 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10271 (ulong)_asc_mcode_chksum);
10272 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10273 _asc_mcode_size) != _asc_mcode_chksum) {
10274 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10275 return (warn_code);
10276 }
10277 warn_code |= AscInitMicroCodeVar(asc_dvc);
10278 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10279 AscEnableInterrupt(iop_base);
10280 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010281}
10282
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010283static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010284{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010285 int i;
10286 PortAddr iop_base;
10287 ushort warn_code;
10288 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010289
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010290 iop_base = asc_dvc->iop_base;
10291 warn_code = 0;
10292 asc_dvc->err_code = 0;
10293 if ((asc_dvc->bus_type &
10294 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10295 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10296 }
10297 AscSetChipControl(iop_base, CC_HALT);
10298 AscSetChipStatus(iop_base, 0);
10299 asc_dvc->bug_fix_cntl = 0;
10300 asc_dvc->pci_fix_asyn_xfer = 0;
10301 asc_dvc->pci_fix_asyn_xfer_always = 0;
10302 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10303 asc_dvc->sdtr_done = 0;
10304 asc_dvc->cur_total_qng = 0;
10305 asc_dvc->is_in_int = 0;
10306 asc_dvc->in_critical_cnt = 0;
10307 asc_dvc->last_q_shortage = 0;
10308 asc_dvc->use_tagged_qng = 0;
10309 asc_dvc->no_scam = 0;
10310 asc_dvc->unit_not_ready = 0;
10311 asc_dvc->queue_full_or_busy = 0;
10312 asc_dvc->redo_scam = 0;
10313 asc_dvc->res2 = 0;
10314 asc_dvc->host_init_sdtr_index = 0;
10315 asc_dvc->cfg->can_tagged_qng = 0;
10316 asc_dvc->cfg->cmd_qng_enabled = 0;
10317 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10318 asc_dvc->init_sdtr = 0;
10319 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10320 asc_dvc->scsi_reset_wait = 3;
10321 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10322 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10323 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10324 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10325 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10326 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10327 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10328 ASC_LIB_VERSION_MINOR;
10329 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10330 asc_dvc->cfg->chip_version = chip_version;
10331 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10332 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10333 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10334 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10335 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10336 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10337 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10338 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10339 asc_dvc->max_sdtr_index = 7;
10340 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10341 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10342 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10343 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10344 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10345 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10346 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10347 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10348 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10349 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10350 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10351 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10352 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10353 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10354 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10355 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10356 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10357 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10358 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10359 asc_dvc->max_sdtr_index = 15;
10360 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10361 AscSetExtraControl(iop_base,
10362 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10363 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10364 AscSetExtraControl(iop_base,
10365 (SEC_ACTIVE_NEGATE |
10366 SEC_ENABLE_FILTER));
10367 }
10368 }
10369 if (asc_dvc->bus_type == ASC_IS_PCI) {
10370 AscSetExtraControl(iop_base,
10371 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010373
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010374 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010375#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010376 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
Matthew Wilcox59fcf842007-07-26 11:54:15 -040010377 if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) {
10378 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10379 asc_dvc->bus_type = ASC_IS_ISAPNP;
10380 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010381 asc_dvc->cfg->isa_dma_channel =
10382 (uchar)AscGetIsaDmaChannel(iop_base);
10383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010384#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010385 for (i = 0; i <= ASC_MAX_TID; i++) {
10386 asc_dvc->cur_dvc_qng[i] = 0;
10387 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10388 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10389 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10390 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10391 }
10392 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010393}
10394
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010395static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010396{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010397 ASCEEP_CONFIG eep_config_buf;
10398 ASCEEP_CONFIG *eep_config;
10399 PortAddr iop_base;
10400 ushort chksum;
10401 ushort warn_code;
10402 ushort cfg_msw, cfg_lsw;
10403 int i;
10404 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010405
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010406 iop_base = asc_dvc->iop_base;
10407 warn_code = 0;
10408 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10409 AscStopQueueExe(iop_base);
10410 if ((AscStopChip(iop_base) == FALSE) ||
10411 (AscGetChipScsiCtrl(iop_base) != 0)) {
10412 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10413 AscResetChipAndScsiBus(asc_dvc);
10414 DvcSleepMilliSecond((ASC_DCNT)
10415 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10416 }
10417 if (AscIsChipHalted(iop_base) == FALSE) {
10418 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10419 return (warn_code);
10420 }
10421 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10422 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10423 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10424 return (warn_code);
10425 }
10426 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10427 cfg_msw = AscGetChipCfgMsw(iop_base);
10428 cfg_lsw = AscGetChipCfgLsw(iop_base);
10429 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10430 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10431 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10432 AscSetChipCfgMsw(iop_base, cfg_msw);
10433 }
10434 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
10435 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
10436 if (chksum == 0) {
10437 chksum = 0xaa55;
10438 }
10439 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10440 warn_code |= ASC_WARN_AUTO_CONFIG;
10441 if (asc_dvc->cfg->chip_version == 3) {
10442 if (eep_config->cfg_lsw != cfg_lsw) {
10443 warn_code |= ASC_WARN_EEPROM_RECOVER;
10444 eep_config->cfg_lsw =
10445 AscGetChipCfgLsw(iop_base);
10446 }
10447 if (eep_config->cfg_msw != cfg_msw) {
10448 warn_code |= ASC_WARN_EEPROM_RECOVER;
10449 eep_config->cfg_msw =
10450 AscGetChipCfgMsw(iop_base);
10451 }
10452 }
10453 }
10454 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
10455 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
10456 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
10457 eep_config->chksum);
10458 if (chksum != eep_config->chksum) {
10459 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
10460 ASC_CHIP_VER_PCI_ULTRA_3050) {
10461 ASC_DBG(1,
10462 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
10463 eep_config->init_sdtr = 0xFF;
10464 eep_config->disc_enable = 0xFF;
10465 eep_config->start_motor = 0xFF;
10466 eep_config->use_cmd_qng = 0;
10467 eep_config->max_total_qng = 0xF0;
10468 eep_config->max_tag_qng = 0x20;
10469 eep_config->cntl = 0xBFFF;
10470 ASC_EEP_SET_CHIP_ID(eep_config, 7);
10471 eep_config->no_scam = 0;
10472 eep_config->adapter_info[0] = 0;
10473 eep_config->adapter_info[1] = 0;
10474 eep_config->adapter_info[2] = 0;
10475 eep_config->adapter_info[3] = 0;
10476 eep_config->adapter_info[4] = 0;
10477 /* Indicate EEPROM-less board. */
10478 eep_config->adapter_info[5] = 0xBB;
10479 } else {
10480 ASC_PRINT
10481 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
10482 write_eep = 1;
10483 warn_code |= ASC_WARN_EEPROM_CHKSUM;
10484 }
10485 }
10486 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
10487 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
10488 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
10489 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
10490 asc_dvc->start_motor = eep_config->start_motor;
10491 asc_dvc->dvc_cntl = eep_config->cntl;
10492 asc_dvc->no_scam = eep_config->no_scam;
10493 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
10494 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
10495 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
10496 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
10497 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
10498 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
10499 if (!AscTestExternalLram(asc_dvc)) {
10500 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
10501 ASC_IS_PCI_ULTRA)) {
10502 eep_config->max_total_qng =
10503 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
10504 eep_config->max_tag_qng =
10505 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
10506 } else {
10507 eep_config->cfg_msw |= 0x0800;
10508 cfg_msw |= 0x0800;
10509 AscSetChipCfgMsw(iop_base, cfg_msw);
10510 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
10511 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
10512 }
10513 } else {
10514 }
10515 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
10516 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
10517 }
10518 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
10519 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
10520 }
10521 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
10522 eep_config->max_tag_qng = eep_config->max_total_qng;
10523 }
10524 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
10525 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
10526 }
10527 asc_dvc->max_total_qng = eep_config->max_total_qng;
10528 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
10529 eep_config->use_cmd_qng) {
10530 eep_config->disc_enable = eep_config->use_cmd_qng;
10531 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10532 }
10533 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
10534 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
10535 }
10536 ASC_EEP_SET_CHIP_ID(eep_config,
10537 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
10538 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
10539 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
10540 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
10541 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
10542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010543
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010544 for (i = 0; i <= ASC_MAX_TID; i++) {
10545 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
10546 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
10547 asc_dvc->cfg->sdtr_period_offset[i] =
10548 (uchar)(ASC_DEF_SDTR_OFFSET |
10549 (asc_dvc->host_init_sdtr_index << 4));
10550 }
10551 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
10552 if (write_eep) {
10553 if ((i =
10554 AscSetEEPConfig(iop_base, eep_config,
10555 asc_dvc->bus_type)) != 0) {
10556 ASC_PRINT1
10557 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
10558 i);
10559 } else {
10560 ASC_PRINT
10561 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
10562 }
10563 }
10564 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010565}
10566
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010567static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010568{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010569 int i;
10570 ushort warn_code;
10571 PortAddr iop_base;
10572 ASC_PADDR phy_addr;
10573 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010575 iop_base = asc_dvc->iop_base;
10576 warn_code = 0;
10577 for (i = 0; i <= ASC_MAX_TID; i++) {
10578 AscPutMCodeInitSDTRAtID(iop_base, i,
10579 asc_dvc->cfg->sdtr_period_offset[i]
10580 );
10581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010582
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010583 AscInitQLinkVar(asc_dvc);
10584 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
10585 asc_dvc->cfg->disc_enable);
10586 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
10587 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010588
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010589 /* Align overrun buffer on an 8 byte boundary. */
10590 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
10591 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
10592 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
10593 (uchar *)&phy_addr, 1);
10594 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
10595 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
10596 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010597
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010598 asc_dvc->cfg->mcode_date =
10599 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
10600 asc_dvc->cfg->mcode_version =
10601 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010602
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010603 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10604 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10605 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10606 return (warn_code);
10607 }
10608 if (AscStartChip(iop_base) != 1) {
10609 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10610 return (warn_code);
10611 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010612
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010613 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010614}
10615
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010616static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010617{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010618 PortAddr iop_base;
10619 ushort q_addr;
10620 ushort saved_word;
10621 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010622
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010623 iop_base = asc_dvc->iop_base;
10624 sta = 0;
10625 q_addr = ASC_QNO_TO_QADDR(241);
10626 saved_word = AscReadLramWord(iop_base, q_addr);
10627 AscSetChipLramAddr(iop_base, q_addr);
10628 AscSetChipLramData(iop_base, 0x55AA);
10629 DvcSleepMilliSecond(10);
10630 AscSetChipLramAddr(iop_base, q_addr);
10631 if (AscGetChipLramData(iop_base) == 0x55AA) {
10632 sta = 1;
10633 AscWriteLramWord(iop_base, q_addr, saved_word);
10634 }
10635 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010636}
10637
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010638static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010639{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010640 uchar read_back;
10641 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010643 retry = 0;
10644 while (TRUE) {
10645 AscSetChipEEPCmd(iop_base, cmd_reg);
10646 DvcSleepMilliSecond(1);
10647 read_back = AscGetChipEEPCmd(iop_base);
10648 if (read_back == cmd_reg) {
10649 return (1);
10650 }
10651 if (retry++ > ASC_EEP_MAX_RETRY) {
10652 return (0);
10653 }
10654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010655}
10656
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010657static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010658{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010659 ushort read_back;
10660 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010661
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010662 retry = 0;
10663 while (TRUE) {
10664 AscSetChipEEPData(iop_base, data_reg);
10665 DvcSleepMilliSecond(1);
10666 read_back = AscGetChipEEPData(iop_base);
10667 if (read_back == data_reg) {
10668 return (1);
10669 }
10670 if (retry++ > ASC_EEP_MAX_RETRY) {
10671 return (0);
10672 }
10673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010674}
10675
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010676static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010677{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010678 DvcSleepMilliSecond(1);
10679 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010680}
10681
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010682static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010683{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010684 DvcSleepMilliSecond(20);
10685 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010686}
10687
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010688static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010689{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010690 ushort read_wval;
10691 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010692
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010693 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10694 AscWaitEEPRead();
10695 cmd_reg = addr | ASC_EEP_CMD_READ;
10696 AscWriteEEPCmdReg(iop_base, cmd_reg);
10697 AscWaitEEPRead();
10698 read_wval = AscGetChipEEPData(iop_base);
10699 AscWaitEEPRead();
10700 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010701}
10702
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010703static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010704AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010705{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010706 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010707
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010708 read_wval = AscReadEEPWord(iop_base, addr);
10709 if (read_wval != word_val) {
10710 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
10711 AscWaitEEPRead();
10712 AscWriteEEPDataReg(iop_base, word_val);
10713 AscWaitEEPRead();
10714 AscWriteEEPCmdReg(iop_base,
10715 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
10716 AscWaitEEPWrite();
10717 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10718 AscWaitEEPRead();
10719 return (AscReadEEPWord(iop_base, addr));
10720 }
10721 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010722}
10723
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010724static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010725AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010726{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010727 ushort wval;
10728 ushort sum;
10729 ushort *wbuf;
10730 int cfg_beg;
10731 int cfg_end;
10732 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
10733 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010734
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010735 wbuf = (ushort *)cfg_buf;
10736 sum = 0;
10737 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
10738 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10739 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10740 sum += *wbuf;
10741 }
10742 if (bus_type & ASC_IS_VL) {
10743 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10744 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10745 } else {
10746 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10747 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10748 }
10749 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10750 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
10751 if (s_addr <= uchar_end_in_config) {
10752 /*
10753 * Swap all char fields - must unswap bytes already swapped
10754 * by AscReadEEPWord().
10755 */
10756 *wbuf = le16_to_cpu(wval);
10757 } else {
10758 /* Don't swap word field at the end - cntl field. */
10759 *wbuf = wval;
10760 }
10761 sum += wval; /* Checksum treats all EEPROM data as words. */
10762 }
10763 /*
10764 * Read the checksum word which will be compared against 'sum'
10765 * by the caller. Word field already swapped.
10766 */
10767 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10768 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010769}
10770
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010771static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010772AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010773{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010774 int n_error;
10775 ushort *wbuf;
10776 ushort word;
10777 ushort sum;
10778 int s_addr;
10779 int cfg_beg;
10780 int cfg_end;
10781 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010782
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010783 wbuf = (ushort *)cfg_buf;
10784 n_error = 0;
10785 sum = 0;
10786 /* Write two config words; AscWriteEEPWord() will swap bytes. */
10787 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10788 sum += *wbuf;
10789 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10790 n_error++;
10791 }
10792 }
10793 if (bus_type & ASC_IS_VL) {
10794 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10795 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10796 } else {
10797 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10798 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10799 }
10800 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10801 if (s_addr <= uchar_end_in_config) {
10802 /*
10803 * This is a char field. Swap char fields before they are
10804 * swapped again by AscWriteEEPWord().
10805 */
10806 word = cpu_to_le16(*wbuf);
10807 if (word !=
10808 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
10809 n_error++;
10810 }
10811 } else {
10812 /* Don't swap word field at the end - cntl field. */
10813 if (*wbuf !=
10814 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10815 n_error++;
10816 }
10817 }
10818 sum += *wbuf; /* Checksum calculated from word values. */
10819 }
10820 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
10821 *wbuf = sum;
10822 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
10823 n_error++;
10824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010825
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010826 /* Read EEPROM back again. */
10827 wbuf = (ushort *)cfg_buf;
10828 /*
10829 * Read two config words; Byte-swapping done by AscReadEEPWord().
10830 */
10831 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10832 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
10833 n_error++;
10834 }
10835 }
10836 if (bus_type & ASC_IS_VL) {
10837 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10838 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10839 } else {
10840 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10841 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10842 }
10843 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10844 if (s_addr <= uchar_end_in_config) {
10845 /*
10846 * Swap all char fields. Must unswap bytes already swapped
10847 * by AscReadEEPWord().
10848 */
10849 word =
10850 le16_to_cpu(AscReadEEPWord
10851 (iop_base, (uchar)s_addr));
10852 } else {
10853 /* Don't swap word field at the end - cntl field. */
10854 word = AscReadEEPWord(iop_base, (uchar)s_addr);
10855 }
10856 if (*wbuf != word) {
10857 n_error++;
10858 }
10859 }
10860 /* Read checksum; Byte swapping not needed. */
10861 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
10862 n_error++;
10863 }
10864 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010865}
10866
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010867static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010868AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010869{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010870 int retry;
10871 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010872
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010873 retry = 0;
10874 while (TRUE) {
10875 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
10876 bus_type)) == 0) {
10877 break;
10878 }
10879 if (++retry > ASC_EEP_MAX_RETRY) {
10880 break;
10881 }
10882 }
10883 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010884}
10885
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010886static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010887{
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010888 char type = sdev->type;
10889 ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010890
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010891 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
10892 if (!(asc_dvc->init_sdtr & tid_bits)) {
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010893 if ((type == TYPE_ROM) &&
10894 (strncmp(sdev->vendor, "HP ", 3) == 0)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010895 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
10896 }
10897 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010898 if ((type == TYPE_PROCESSOR) ||
10899 (type == TYPE_SCANNER) || (type == TYPE_ROM) ||
10900 (type == TYPE_TAPE)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010901 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
10902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010903
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010904 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
10905 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
Matthew Wilcox47d853c2007-07-26 11:41:33 -040010906 sdev->id,
10907 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010908 }
10909 }
10910 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010911}
10912
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010913static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010914{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010915 uchar byte_data;
10916 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010917
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010918 if (isodd_word(addr)) {
10919 AscSetChipLramAddr(iop_base, addr - 1);
10920 word_data = AscGetChipLramData(iop_base);
10921 byte_data = (uchar)((word_data >> 8) & 0xFF);
10922 } else {
10923 AscSetChipLramAddr(iop_base, addr);
10924 word_data = AscGetChipLramData(iop_base);
10925 byte_data = (uchar)(word_data & 0xFF);
10926 }
10927 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010928}
Linus Torvalds1da177e2005-04-16 15:20:36 -070010929
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010930static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
10931{
10932 ushort word_data;
10933
10934 AscSetChipLramAddr(iop_base, addr);
10935 word_data = AscGetChipLramData(iop_base);
10936 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010937}
10938
10939#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010940static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010941{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010942 ushort val_low, val_high;
10943 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010944
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010945 AscSetChipLramAddr(iop_base, addr);
10946 val_low = AscGetChipLramData(iop_base);
10947 val_high = AscGetChipLramData(iop_base);
10948 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
10949 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010950}
10951#endif /* CC_VERY_LONG_SG_LIST */
10952
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010953static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010954{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010955 AscSetChipLramAddr(iop_base, addr);
10956 AscSetChipLramData(iop_base, word_val);
10957 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010958}
10959
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010960static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010961{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010962 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010963
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010964 if (isodd_word(addr)) {
10965 addr--;
10966 word_data = AscReadLramWord(iop_base, addr);
10967 word_data &= 0x00FF;
10968 word_data |= (((ushort)byte_val << 8) & 0xFF00);
10969 } else {
10970 word_data = AscReadLramWord(iop_base, addr);
10971 word_data &= 0xFF00;
10972 word_data |= ((ushort)byte_val & 0x00FF);
10973 }
10974 AscWriteLramWord(iop_base, addr, word_data);
10975 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010976}
10977
10978/*
10979 * Copy 2 bytes to LRAM.
10980 *
10981 * The source data is assumed to be in little-endian order in memory
10982 * and is maintained in little-endian order when written to LRAM.
10983 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010984static void
10985AscMemWordCopyPtrToLram(PortAddr iop_base,
10986 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010987{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010988 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010989
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010990 AscSetChipLramAddr(iop_base, s_addr);
10991 for (i = 0; i < 2 * words; i += 2) {
10992 /*
10993 * On a little-endian system the second argument below
10994 * produces a little-endian ushort which is written to
10995 * LRAM in little-endian order. On a big-endian system
10996 * the second argument produces a big-endian ushort which
10997 * is "transparently" byte-swapped by outpw() and written
10998 * in little-endian order to LRAM.
10999 */
11000 outpw(iop_base + IOP_RAM_DATA,
11001 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
11002 }
11003 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011004}
11005
11006/*
11007 * Copy 4 bytes to LRAM.
11008 *
11009 * The source data is assumed to be in little-endian order in memory
11010 * and is maintained in little-endian order when writen to LRAM.
11011 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011012static void
11013AscMemDWordCopyPtrToLram(PortAddr iop_base,
11014 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011015{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011016 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011017
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011018 AscSetChipLramAddr(iop_base, s_addr);
11019 for (i = 0; i < 4 * dwords; i += 4) {
11020 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11021 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11022 }
11023 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011024}
11025
11026/*
11027 * Copy 2 bytes from LRAM.
11028 *
11029 * The source data is assumed to be in little-endian order in LRAM
11030 * and is maintained in little-endian order when written to memory.
11031 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011032static void
11033AscMemWordCopyPtrFromLram(PortAddr iop_base,
11034 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011035{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011036 int i;
11037 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011038
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011039 AscSetChipLramAddr(iop_base, s_addr);
11040 for (i = 0; i < 2 * words; i += 2) {
11041 word = inpw(iop_base + IOP_RAM_DATA);
11042 d_buffer[i] = word & 0xff;
11043 d_buffer[i + 1] = (word >> 8) & 0xff;
11044 }
11045 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011046}
11047
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011048static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011049{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011050 ASC_DCNT sum;
11051 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011052
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011053 sum = 0L;
11054 for (i = 0; i < words; i++, s_addr += 2) {
11055 sum += AscReadLramWord(iop_base, s_addr);
11056 }
11057 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011058}
11059
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011060static void
11061AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011062{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011063 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011064
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011065 AscSetChipLramAddr(iop_base, s_addr);
11066 for (i = 0; i < words; i++) {
11067 AscSetChipLramData(iop_base, set_wval);
11068 }
11069 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011070}
11071
Linus Torvalds1da177e2005-04-16 15:20:36 -070011072/*
11073 * --- Adv Library Functions
11074 */
11075
11076/* a_mcode.h */
11077
11078/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011079static unsigned char _adv_asc3550_buf[] = {
11080 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11081 0x01, 0x00, 0x48, 0xe4,
11082 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11083 0x28, 0x0e, 0x9e, 0xe7,
11084 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11085 0x55, 0xf0, 0x01, 0xf6,
11086 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11087 0x00, 0xec, 0x85, 0xf0,
11088 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11089 0x86, 0xf0, 0xb4, 0x00,
11090 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11091 0xaa, 0x18, 0x02, 0x80,
11092 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11093 0x00, 0x57, 0x01, 0xea,
11094 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11095 0x03, 0xe6, 0xb6, 0x00,
11096 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11097 0x02, 0x4a, 0xb9, 0x54,
11098 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11099 0x3e, 0x00, 0x80, 0x00,
11100 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11101 0x74, 0x01, 0x76, 0x01,
11102 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11103 0x4c, 0x1c, 0xbb, 0x55,
11104 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11105 0x03, 0xf7, 0x06, 0xf7,
11106 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11107 0x30, 0x13, 0x64, 0x15,
11108 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11109 0x04, 0xea, 0x5d, 0xf0,
11110 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11111 0xcc, 0x00, 0x20, 0x01,
11112 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11113 0x40, 0x13, 0x30, 0x1c,
11114 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11115 0x59, 0xf0, 0xa7, 0xf0,
11116 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11117 0xa4, 0x00, 0xb5, 0x00,
11118 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11119 0x14, 0x0e, 0x02, 0x10,
11120 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11121 0x10, 0x15, 0x14, 0x15,
11122 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11123 0x91, 0x44, 0x0a, 0x45,
11124 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11125 0x83, 0x59, 0x05, 0xe6,
11126 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11127 0x02, 0xfa, 0x03, 0xfa,
11128 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11129 0x9e, 0x00, 0xa8, 0x00,
11130 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11131 0x7a, 0x01, 0xc0, 0x01,
11132 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11133 0x69, 0x08, 0xba, 0x08,
11134 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11135 0xf1, 0x10, 0x06, 0x12,
11136 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11137 0x8a, 0x15, 0xc6, 0x17,
11138 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11139 0x0e, 0x47, 0x48, 0x47,
11140 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11141 0x14, 0x56, 0x77, 0x57,
11142 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11143 0xf0, 0x29, 0x02, 0xfe,
11144 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11145 0xfe, 0x80, 0x01, 0xff,
11146 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11147 0x00, 0xfe, 0x57, 0x24,
11148 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11149 0x00, 0x00, 0xff, 0x08,
11150 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11151 0xff, 0xff, 0xff, 0x0f,
11152 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11153 0xfe, 0x04, 0xf7, 0xcf,
11154 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11155 0x0b, 0x3c, 0x2a, 0xfe,
11156 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11157 0xfe, 0xf0, 0x01, 0xfe,
11158 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11159 0x02, 0xfe, 0xd4, 0x0c,
11160 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11161 0x1c, 0x05, 0xfe, 0xa6,
11162 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11163 0xf0, 0xfe, 0x86, 0x02,
11164 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11165 0xfe, 0x46, 0xf0, 0xfe,
11166 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11167 0x44, 0x02, 0xfe, 0x44,
11168 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11169 0xa0, 0x17, 0x06, 0x18,
11170 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11171 0x1e, 0x1c, 0xfe, 0xe9,
11172 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11173 0x0a, 0x6b, 0x01, 0x9e,
11174 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11175 0x01, 0x82, 0xfe, 0xbd,
11176 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11177 0x58, 0x1c, 0x17, 0x06,
11178 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11179 0xfe, 0x94, 0x02, 0xfe,
11180 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11181 0x01, 0xfe, 0x54, 0x0f,
11182 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11183 0x69, 0x10, 0x17, 0x06,
11184 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11185 0xf6, 0xc7, 0x01, 0xfe,
11186 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11187 0x02, 0x29, 0x0a, 0x40,
11188 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11189 0x58, 0x0a, 0x99, 0x01,
11190 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11191 0x2a, 0x46, 0xfe, 0x02,
11192 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11193 0x01, 0xfe, 0x07, 0x4b,
11194 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11195 0xfe, 0x56, 0x03, 0xfe,
11196 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11197 0xfe, 0x9f, 0xf0, 0xfe,
11198 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11199 0x1c, 0xeb, 0x09, 0x04,
11200 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11201 0x01, 0x0e, 0xac, 0x75,
11202 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11203 0xfe, 0x82, 0xf0, 0xfe,
11204 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11205 0x32, 0x1f, 0xfe, 0xb4,
11206 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11207 0x0a, 0xf0, 0xfe, 0x7a,
11208 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11209 0x01, 0x33, 0x8f, 0xfe,
11210 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11211 0xf7, 0xfe, 0x48, 0x1c,
11212 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11213 0x0a, 0xca, 0x01, 0x0e,
11214 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11215 0x2c, 0x01, 0x33, 0x8f,
11216 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11217 0xfe, 0x3c, 0x04, 0x1f,
11218 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11219 0x12, 0x2b, 0xff, 0x02,
11220 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11221 0x22, 0x30, 0x2e, 0xd5,
11222 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11223 0xfe, 0x4c, 0x54, 0x64,
11224 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11225 0xfe, 0x2a, 0x13, 0x2f,
11226 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11227 0xd3, 0xfa, 0xef, 0x86,
11228 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11229 0x1d, 0xfe, 0x1c, 0x12,
11230 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11231 0x70, 0x0c, 0x02, 0x22,
11232 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11233 0x01, 0x33, 0x02, 0x29,
11234 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11235 0x80, 0xfe, 0x31, 0xe4,
11236 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11237 0xfe, 0x70, 0x12, 0x49,
11238 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11239 0x80, 0x05, 0xfe, 0x31,
11240 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11241 0x28, 0xfe, 0x42, 0x12,
11242 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11243 0x11, 0xfe, 0xe3, 0x00,
11244 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11245 0x64, 0x05, 0x83, 0x24,
11246 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11247 0x09, 0x48, 0x01, 0x08,
11248 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11249 0x86, 0x24, 0x06, 0x12,
11250 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11251 0x01, 0xa7, 0x14, 0x92,
11252 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11253 0x02, 0x22, 0x05, 0xfe,
11254 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11255 0x47, 0x01, 0xa7, 0x26,
11256 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11257 0x01, 0xfe, 0xaa, 0x14,
11258 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11259 0x05, 0x50, 0xb4, 0x0c,
11260 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11261 0x13, 0x01, 0xfe, 0x14,
11262 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11263 0xff, 0x02, 0x00, 0x57,
11264 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11265 0x72, 0x06, 0x49, 0x04,
11266 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11267 0x06, 0x11, 0x9a, 0x01,
11268 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11269 0x01, 0xa7, 0xec, 0x72,
11270 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11271 0xfe, 0x0a, 0xf0, 0xfe,
11272 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11273 0x8d, 0x81, 0x02, 0x22,
11274 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11275 0x01, 0x08, 0x15, 0x00,
11276 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11277 0x00, 0x02, 0xfe, 0x32,
11278 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11279 0xfe, 0x1b, 0x00, 0x01,
11280 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11281 0x08, 0x15, 0x06, 0x01,
11282 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11283 0x9a, 0x81, 0x4b, 0x1d,
11284 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11285 0x45, 0xfe, 0x32, 0x12,
11286 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11287 0xfe, 0x32, 0x07, 0x8d,
11288 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11289 0x06, 0x15, 0x19, 0x02,
11290 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11291 0x90, 0x77, 0xfe, 0xca,
11292 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11293 0x10, 0xfe, 0x0e, 0x12,
11294 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11295 0x83, 0xe7, 0xc4, 0xa1,
11296 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11297 0x40, 0x12, 0x58, 0x01,
11298 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11299 0x51, 0x83, 0xfb, 0xfe,
11300 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11301 0xfe, 0x40, 0x50, 0xfe,
11302 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11303 0xfe, 0x2a, 0x12, 0xfe,
11304 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11305 0x85, 0x01, 0xa8, 0xfe,
11306 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11307 0x18, 0x57, 0xfb, 0xfe,
11308 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11309 0x0c, 0x39, 0x18, 0x3a,
11310 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11311 0x11, 0x65, 0xfe, 0x48,
11312 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11313 0xdd, 0xb8, 0xfe, 0x80,
11314 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11315 0xfe, 0x7a, 0x08, 0x8d,
11316 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11317 0x10, 0x61, 0x04, 0x06,
11318 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11319 0x12, 0xfe, 0x2e, 0x1c,
11320 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11321 0x52, 0x12, 0xfe, 0x2c,
11322 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11323 0x08, 0xfe, 0x8a, 0x10,
11324 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11325 0x24, 0x0a, 0xab, 0xfe,
11326 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11327 0x1c, 0x12, 0xb5, 0xfe,
11328 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11329 0x1c, 0x06, 0x16, 0x9d,
11330 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11331 0x14, 0x92, 0x01, 0x33,
11332 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11333 0xfe, 0x74, 0x18, 0x1c,
11334 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11335 0x01, 0xe6, 0x1e, 0x27,
11336 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11337 0x09, 0x04, 0x6a, 0xfe,
11338 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11339 0xfe, 0x83, 0x80, 0xfe,
11340 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11341 0x27, 0xfe, 0x40, 0x59,
11342 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11343 0x7c, 0xbe, 0x54, 0xbf,
11344 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11345 0x79, 0x56, 0x68, 0x57,
11346 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11347 0xa2, 0x23, 0x0c, 0x7b,
11348 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11349 0x16, 0xd7, 0x79, 0x39,
11350 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11351 0xfe, 0x10, 0x58, 0xfe,
11352 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
11353 0x19, 0x16, 0xd7, 0x09,
11354 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
11355 0xfe, 0x10, 0x90, 0xfe,
11356 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
11357 0x11, 0x9b, 0x09, 0x04,
11358 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
11359 0xfe, 0x0c, 0x58, 0xfe,
11360 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
11361 0x0b, 0xfe, 0x1a, 0x12,
11362 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
11363 0x14, 0x7a, 0x01, 0x33,
11364 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
11365 0xfe, 0xed, 0x19, 0xbf,
11366 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
11367 0x34, 0xfe, 0x74, 0x10,
11368 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
11369 0x84, 0x05, 0xcb, 0x1c,
11370 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
11371 0xf0, 0xfe, 0xc4, 0x0a,
11372 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
11373 0xce, 0xf0, 0xfe, 0xca,
11374 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
11375 0x22, 0x00, 0x02, 0x5a,
11376 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
11377 0xfe, 0xd0, 0xf0, 0xfe,
11378 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
11379 0x4c, 0xfe, 0x10, 0x10,
11380 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
11381 0x2a, 0x13, 0xfe, 0x4e,
11382 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
11383 0x16, 0x32, 0x2a, 0x73,
11384 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
11385 0x32, 0x8c, 0xfe, 0x48,
11386 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
11387 0xdb, 0x10, 0x11, 0xfe,
11388 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
11389 0x22, 0x30, 0x2e, 0xd8,
11390 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
11391 0x45, 0x0f, 0xfe, 0x42,
11392 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
11393 0x09, 0x04, 0x0b, 0xfe,
11394 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
11395 0x00, 0x21, 0xfe, 0xa6,
11396 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
11397 0xfe, 0xe2, 0x10, 0x01,
11398 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
11399 0x01, 0x6f, 0x02, 0x29,
11400 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
11401 0x01, 0x86, 0x3e, 0x0b,
11402 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
11403 0x3e, 0x0b, 0x0f, 0xfe,
11404 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
11405 0xe8, 0x59, 0x11, 0x2d,
11406 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
11407 0x04, 0x0b, 0x84, 0x3e,
11408 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
11409 0x09, 0x04, 0x1b, 0xfe,
11410 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
11411 0x1c, 0x1c, 0xfe, 0x9d,
11412 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
11413 0xfe, 0x15, 0x00, 0xfe,
11414 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
11415 0x0f, 0xfe, 0x47, 0x00,
11416 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
11417 0xab, 0x70, 0x05, 0x6b,
11418 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
11419 0x1c, 0x42, 0x59, 0x01,
11420 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
11421 0x00, 0x37, 0x97, 0x01,
11422 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
11423 0x1d, 0xfe, 0xce, 0x45,
11424 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
11425 0x57, 0x05, 0x51, 0xfe,
11426 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
11427 0x46, 0x09, 0x04, 0x1d,
11428 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
11429 0x99, 0x01, 0x0e, 0xfe,
11430 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
11431 0xfe, 0xee, 0x14, 0xee,
11432 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
11433 0x13, 0x02, 0x29, 0x1e,
11434 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
11435 0xce, 0x1e, 0x2d, 0x47,
11436 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
11437 0x12, 0x4d, 0x01, 0xfe,
11438 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
11439 0xf0, 0x0d, 0xfe, 0x02,
11440 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
11441 0xf6, 0xfe, 0x34, 0x01,
11442 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
11443 0xaf, 0xfe, 0x02, 0xea,
11444 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
11445 0x05, 0xfe, 0x38, 0x01,
11446 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
11447 0x0c, 0xfe, 0x62, 0x01,
11448 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
11449 0x03, 0x23, 0x03, 0x1e,
11450 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
11451 0x71, 0x13, 0xfe, 0x24,
11452 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
11453 0xdc, 0xfe, 0x73, 0x57,
11454 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
11455 0x80, 0x5d, 0x03, 0xfe,
11456 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
11457 0x75, 0x03, 0x09, 0x04,
11458 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
11459 0xfe, 0x1e, 0x80, 0xe1,
11460 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
11461 0x90, 0xa3, 0xfe, 0x3c,
11462 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
11463 0x16, 0x2f, 0x07, 0x2d,
11464 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
11465 0xe8, 0x11, 0xfe, 0xe9,
11466 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
11467 0x1e, 0x1c, 0xfe, 0x14,
11468 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
11469 0x09, 0x04, 0x4f, 0xfe,
11470 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
11471 0x40, 0x12, 0x20, 0x63,
11472 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
11473 0x1c, 0x05, 0xfe, 0xac,
11474 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
11475 0xfe, 0xb0, 0x00, 0xfe,
11476 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
11477 0x24, 0x69, 0x12, 0xc9,
11478 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
11479 0x90, 0x4d, 0xfe, 0x91,
11480 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
11481 0xfe, 0x90, 0x4d, 0xfe,
11482 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
11483 0x46, 0x1e, 0x20, 0xed,
11484 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
11485 0x70, 0xfe, 0x14, 0x1c,
11486 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
11487 0xfe, 0x07, 0xe6, 0x1d,
11488 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
11489 0xfa, 0xef, 0xfe, 0x42,
11490 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
11491 0xfe, 0x36, 0x12, 0xf0,
11492 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
11493 0x3d, 0x75, 0x07, 0x10,
11494 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
11495 0x10, 0x07, 0x7e, 0x45,
11496 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
11497 0xfe, 0x01, 0xec, 0x97,
11498 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
11499 0x27, 0x01, 0xda, 0xfe,
11500 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
11501 0xfe, 0x48, 0x12, 0x07,
11502 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
11503 0xfe, 0x3e, 0x11, 0x07,
11504 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
11505 0x11, 0x07, 0x19, 0xfe,
11506 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
11507 0x01, 0x08, 0x8c, 0x43,
11508 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
11509 0x7e, 0x02, 0x29, 0x2b,
11510 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
11511 0xfc, 0x10, 0x09, 0x04,
11512 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
11513 0xc6, 0x10, 0x1e, 0x58,
11514 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
11515 0x54, 0x18, 0x55, 0x23,
11516 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
11517 0xa5, 0xc0, 0x38, 0xc1,
11518 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
11519 0x05, 0xfa, 0x4e, 0xfe,
11520 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
11521 0x0c, 0x56, 0x18, 0x57,
11522 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
11523 0x00, 0x56, 0xfe, 0xa1,
11524 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
11525 0x58, 0xfe, 0x1f, 0x40,
11526 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
11527 0x31, 0x57, 0xfe, 0x44,
11528 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
11529 0x8a, 0x50, 0x05, 0x39,
11530 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
11531 0x12, 0xcd, 0x02, 0x5b,
11532 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
11533 0x2f, 0x07, 0x9b, 0x21,
11534 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
11535 0x39, 0x68, 0x3a, 0xfe,
11536 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
11537 0x51, 0xfe, 0x8e, 0x51,
11538 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
11539 0x01, 0x08, 0x25, 0x32,
11540 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
11541 0x3b, 0x02, 0x44, 0x01,
11542 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
11543 0x01, 0x08, 0x1f, 0xa2,
11544 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
11545 0x00, 0x28, 0x84, 0x49,
11546 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
11547 0x78, 0x3d, 0xfe, 0xda,
11548 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
11549 0x05, 0xc6, 0x28, 0x84,
11550 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
11551 0x14, 0xfe, 0x03, 0x17,
11552 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
11553 0xfe, 0xaa, 0x14, 0x02,
11554 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
11555 0x21, 0x44, 0x01, 0xfe,
11556 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
11557 0xfe, 0x4a, 0xf4, 0x0b,
11558 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
11559 0x85, 0x02, 0x5b, 0x05,
11560 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
11561 0xd8, 0x14, 0x02, 0x5c,
11562 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
11563 0x01, 0x08, 0x23, 0x72,
11564 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
11565 0x12, 0x5e, 0x2b, 0x01,
11566 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
11567 0x1c, 0xfe, 0xff, 0x7f,
11568 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
11569 0x57, 0x48, 0x8b, 0x1c,
11570 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
11571 0x00, 0x57, 0x48, 0x8b,
11572 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
11573 0x03, 0x0a, 0x50, 0x01,
11574 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
11575 0x54, 0xfe, 0x00, 0xf4,
11576 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
11577 0x03, 0x7c, 0x63, 0x27,
11578 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
11579 0xfe, 0x82, 0x4a, 0xfe,
11580 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
11581 0x42, 0x48, 0x5f, 0x60,
11582 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
11583 0x1f, 0xfe, 0xa2, 0x14,
11584 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
11585 0xcc, 0x12, 0x49, 0x04,
11586 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
11587 0xe8, 0x13, 0x3b, 0x13,
11588 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
11589 0xa1, 0xff, 0x02, 0x83,
11590 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
11591 0x13, 0x06, 0xfe, 0x56,
11592 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
11593 0x64, 0x00, 0x17, 0x93,
11594 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
11595 0xc8, 0x00, 0x8e, 0xe4,
11596 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
11597 0x01, 0xba, 0xfe, 0x4e,
11598 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
11599 0xfe, 0x60, 0x14, 0xfe,
11600 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
11601 0xfe, 0x22, 0x13, 0x1c,
11602 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
11603 0xfe, 0x9c, 0x14, 0xb7,
11604 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
11605 0xfe, 0x9c, 0x14, 0xb7,
11606 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
11607 0xfe, 0xb4, 0x56, 0xfe,
11608 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
11609 0xe5, 0x15, 0x0b, 0x01,
11610 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
11611 0x49, 0x01, 0x08, 0x03,
11612 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
11613 0x15, 0x06, 0x01, 0x08,
11614 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
11615 0x4a, 0x01, 0x08, 0x03,
11616 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
11617 0xfe, 0x49, 0xf4, 0x00,
11618 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
11619 0x08, 0x2f, 0x07, 0xfe,
11620 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
11621 0x01, 0x43, 0x1e, 0xcd,
11622 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11623 0xed, 0x88, 0x07, 0x10,
11624 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
11625 0x80, 0x01, 0x0e, 0x88,
11626 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
11627 0x88, 0x03, 0x0a, 0x42,
11628 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11629 0xfe, 0x80, 0x80, 0xf2,
11630 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
11631 0x01, 0x82, 0x03, 0x17,
11632 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
11633 0xfe, 0x24, 0x1c, 0xfe,
11634 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
11635 0x91, 0x1d, 0x66, 0xfe,
11636 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
11637 0xda, 0x10, 0x17, 0x10,
11638 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
11639 0x05, 0xfe, 0x66, 0x01,
11640 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
11641 0xfe, 0x3c, 0x50, 0x66,
11642 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
11643 0x40, 0x16, 0xfe, 0xb6,
11644 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
11645 0x10, 0x71, 0xfe, 0x83,
11646 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
11647 0xfe, 0x62, 0x16, 0xfe,
11648 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
11649 0xfe, 0x98, 0xe7, 0x00,
11650 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
11651 0xfe, 0x30, 0xbc, 0xfe,
11652 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
11653 0xc5, 0x90, 0xfe, 0x9a,
11654 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
11655 0x42, 0x10, 0xfe, 0x02,
11656 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
11657 0xfe, 0x1d, 0xf7, 0x4f,
11658 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
11659 0x47, 0xfe, 0x83, 0x58,
11660 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
11661 0xfe, 0xdd, 0x00, 0x63,
11662 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
11663 0x06, 0x37, 0x95, 0xa9,
11664 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
11665 0x18, 0x1c, 0x1a, 0x5d,
11666 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
11667 0xe1, 0x10, 0x78, 0x2c,
11668 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
11669 0x13, 0x3c, 0x8a, 0x0a,
11670 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
11671 0xe3, 0xfe, 0x00, 0xcc,
11672 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
11673 0x0e, 0xf2, 0x01, 0x6f,
11674 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
11675 0xf6, 0xfe, 0xd6, 0xf0,
11676 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
11677 0x15, 0x00, 0x59, 0x76,
11678 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
11679 0x11, 0x2d, 0x01, 0x6f,
11680 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
11681 0xc8, 0xfe, 0x48, 0x55,
11682 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
11683 0x99, 0x01, 0x0e, 0xf0,
11684 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
11685 0x75, 0x03, 0x0a, 0x42,
11686 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
11687 0x0e, 0x73, 0x75, 0x03,
11688 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
11689 0xfe, 0x3a, 0x45, 0x5b,
11690 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
11691 0xfe, 0x02, 0xe6, 0x1b,
11692 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
11693 0xfe, 0x94, 0x00, 0xfe,
11694 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
11695 0xe6, 0x2c, 0xfe, 0x4e,
11696 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
11697 0x03, 0x07, 0x7a, 0xfe,
11698 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
11699 0x07, 0x1b, 0xfe, 0x5a,
11700 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
11701 0x24, 0x2c, 0xdc, 0x07,
11702 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
11703 0x9f, 0xad, 0x03, 0x14,
11704 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
11705 0x03, 0x25, 0xfe, 0xca,
11706 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
11707 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011708};
11709
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011710static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
11711static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011712
11713/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011714static unsigned char _adv_asc38C0800_buf[] = {
11715 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
11716 0x01, 0x00, 0x48, 0xe4,
11717 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
11718 0x1c, 0x0f, 0x00, 0xf6,
11719 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
11720 0x09, 0xe7, 0x55, 0xf0,
11721 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
11722 0x18, 0xf4, 0x08, 0x00,
11723 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
11724 0x86, 0xf0, 0xb1, 0xf0,
11725 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
11726 0x3c, 0x00, 0xbb, 0x00,
11727 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
11728 0xba, 0x13, 0x18, 0x40,
11729 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
11730 0x6e, 0x01, 0x74, 0x01,
11731 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
11732 0xc0, 0x00, 0x01, 0x01,
11733 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
11734 0x08, 0x12, 0x02, 0x4a,
11735 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
11736 0x5d, 0xf0, 0x02, 0xfa,
11737 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
11738 0x68, 0x01, 0x6a, 0x01,
11739 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
11740 0x06, 0x13, 0x4c, 0x1c,
11741 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
11742 0x0f, 0x00, 0x47, 0x00,
11743 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
11744 0x4e, 0x1c, 0x10, 0x44,
11745 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
11746 0x05, 0x00, 0x34, 0x00,
11747 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
11748 0x42, 0x0c, 0x12, 0x0f,
11749 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
11750 0x00, 0x4e, 0x42, 0x54,
11751 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11752 0x59, 0xf0, 0xb8, 0xf0,
11753 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
11754 0x19, 0x00, 0x33, 0x00,
11755 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
11756 0xe7, 0x00, 0xe2, 0x03,
11757 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
11758 0x12, 0x13, 0x24, 0x14,
11759 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
11760 0x36, 0x1c, 0x08, 0x44,
11761 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
11762 0x3a, 0x55, 0x83, 0x55,
11763 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
11764 0x0c, 0xf0, 0x04, 0xf8,
11765 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
11766 0xa8, 0x00, 0xaa, 0x00,
11767 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
11768 0xc4, 0x01, 0xc6, 0x01,
11769 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
11770 0x68, 0x08, 0x69, 0x08,
11771 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
11772 0xed, 0x10, 0xf1, 0x10,
11773 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
11774 0x1e, 0x13, 0x46, 0x14,
11775 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
11776 0xca, 0x18, 0xe6, 0x19,
11777 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
11778 0xf0, 0x2b, 0x02, 0xfe,
11779 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
11780 0xfe, 0x84, 0x01, 0xff,
11781 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11782 0x00, 0xfe, 0x57, 0x24,
11783 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
11784 0x00, 0x00, 0xff, 0x08,
11785 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11786 0xff, 0xff, 0xff, 0x11,
11787 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11788 0xfe, 0x04, 0xf7, 0xd6,
11789 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
11790 0x0a, 0x42, 0x2c, 0xfe,
11791 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
11792 0xfe, 0xf4, 0x01, 0xfe,
11793 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
11794 0x02, 0xfe, 0xc8, 0x0d,
11795 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11796 0x1c, 0x03, 0xfe, 0xa6,
11797 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
11798 0xf0, 0xfe, 0x8a, 0x02,
11799 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
11800 0xfe, 0x46, 0xf0, 0xfe,
11801 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11802 0x48, 0x02, 0xfe, 0x44,
11803 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
11804 0xaa, 0x18, 0x06, 0x14,
11805 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
11806 0x1e, 0x1c, 0xfe, 0xe9,
11807 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
11808 0x09, 0x70, 0x01, 0xa8,
11809 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
11810 0x01, 0x87, 0xfe, 0xbd,
11811 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11812 0x58, 0x1c, 0x18, 0x06,
11813 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
11814 0xfe, 0x98, 0x02, 0xfe,
11815 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
11816 0x01, 0xfe, 0x48, 0x10,
11817 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
11818 0x69, 0x10, 0x18, 0x06,
11819 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
11820 0xf6, 0xce, 0x01, 0xfe,
11821 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
11822 0x82, 0x16, 0x02, 0x2b,
11823 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
11824 0xfe, 0x41, 0x58, 0x09,
11825 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
11826 0x82, 0x16, 0x02, 0x2b,
11827 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
11828 0xfe, 0x77, 0x57, 0xfe,
11829 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
11830 0xfe, 0x40, 0x1c, 0x1c,
11831 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
11832 0x03, 0xfe, 0x11, 0xf0,
11833 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
11834 0xfe, 0x11, 0x00, 0x02,
11835 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
11836 0x21, 0x22, 0xa3, 0xb7,
11837 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
11838 0x12, 0xd1, 0x1c, 0xd9,
11839 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
11840 0xfe, 0xe4, 0x00, 0x27,
11841 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
11842 0x06, 0xf0, 0xfe, 0xc8,
11843 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
11844 0x70, 0x28, 0x17, 0xfe,
11845 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
11846 0xf9, 0x2c, 0x99, 0x19,
11847 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
11848 0x74, 0x01, 0xaf, 0x8c,
11849 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
11850 0x8d, 0x51, 0x64, 0x79,
11851 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
11852 0xfe, 0x6a, 0x02, 0x02,
11853 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
11854 0xfe, 0x3c, 0x04, 0x3b,
11855 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
11856 0x00, 0x10, 0x01, 0x0b,
11857 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
11858 0xfe, 0x4c, 0x44, 0xfe,
11859 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
11860 0xda, 0x4f, 0x79, 0x2a,
11861 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
11862 0xfe, 0x2a, 0x13, 0x32,
11863 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
11864 0x54, 0x6b, 0xda, 0xfe,
11865 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
11866 0x08, 0x13, 0x32, 0x07,
11867 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
11868 0x08, 0x05, 0x06, 0x4d,
11869 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
11870 0x2d, 0x12, 0xfe, 0xe6,
11871 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
11872 0x02, 0x2b, 0xfe, 0x42,
11873 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
11874 0xfe, 0x87, 0x80, 0xfe,
11875 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
11876 0x07, 0x19, 0xfe, 0x7c,
11877 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
11878 0x17, 0xfe, 0x90, 0x05,
11879 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
11880 0xa0, 0x00, 0x28, 0xfe,
11881 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
11882 0x34, 0xfe, 0x89, 0x48,
11883 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
11884 0x12, 0xfe, 0xe3, 0x00,
11885 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11886 0x70, 0x05, 0x88, 0x25,
11887 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
11888 0x09, 0x48, 0xff, 0x02,
11889 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
11890 0x08, 0x53, 0x05, 0xcb,
11891 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
11892 0x05, 0x1b, 0xfe, 0x22,
11893 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
11894 0x0d, 0x00, 0x01, 0x36,
11895 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
11896 0x03, 0x5c, 0x28, 0xfe,
11897 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
11898 0x05, 0x1f, 0xfe, 0x02,
11899 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
11900 0x01, 0x4b, 0x12, 0xfe,
11901 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
11902 0x12, 0x03, 0x45, 0x28,
11903 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
11904 0x43, 0x48, 0xc4, 0xcc,
11905 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
11906 0x6e, 0x41, 0x01, 0xb2,
11907 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
11908 0xfe, 0xcc, 0x15, 0x1d,
11909 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
11910 0x45, 0xc1, 0x0c, 0x45,
11911 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
11912 0xe2, 0x00, 0x27, 0xdb,
11913 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
11914 0xfe, 0x06, 0xf0, 0xfe,
11915 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
11916 0x16, 0x19, 0x01, 0x0b,
11917 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
11918 0xfe, 0x99, 0xa4, 0x01,
11919 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
11920 0x12, 0x08, 0x05, 0x1a,
11921 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
11922 0x0b, 0x16, 0x00, 0x01,
11923 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
11924 0xe2, 0x6c, 0x58, 0xbe,
11925 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
11926 0xfe, 0x09, 0x6f, 0xba,
11927 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
11928 0xfe, 0x54, 0x07, 0x1c,
11929 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
11930 0x07, 0x02, 0x24, 0x01,
11931 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
11932 0x2c, 0x90, 0xfe, 0xae,
11933 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
11934 0x37, 0x22, 0x20, 0x07,
11935 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
11936 0xfe, 0x06, 0x10, 0xfe,
11937 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
11938 0x37, 0x01, 0xb3, 0xb8,
11939 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
11940 0x50, 0xfe, 0x44, 0x51,
11941 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
11942 0x14, 0x5f, 0xfe, 0x0c,
11943 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
11944 0x14, 0x3e, 0xfe, 0x4a,
11945 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11946 0x90, 0x0c, 0x60, 0x14,
11947 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
11948 0xfe, 0x44, 0x90, 0xfe,
11949 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
11950 0x0c, 0x5e, 0x14, 0x5f,
11951 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
11952 0x14, 0x3c, 0x21, 0x0c,
11953 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
11954 0x27, 0xdd, 0xfe, 0x9e,
11955 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
11956 0x9a, 0x08, 0xc6, 0xfe,
11957 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
11958 0x95, 0x86, 0x02, 0x24,
11959 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
11960 0x06, 0xfe, 0x10, 0x12,
11961 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
11962 0x1c, 0x02, 0xfe, 0x18,
11963 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
11964 0x2c, 0x1c, 0xfe, 0xaa,
11965 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
11966 0xde, 0x09, 0xfe, 0xb7,
11967 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
11968 0xfe, 0xf1, 0x18, 0xfe,
11969 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
11970 0x14, 0x59, 0xfe, 0x95,
11971 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
11972 0xfe, 0xf0, 0x08, 0xb5,
11973 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
11974 0x0b, 0xb6, 0xfe, 0xbf,
11975 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
11976 0x12, 0xc2, 0xfe, 0xd2,
11977 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
11978 0x06, 0x17, 0x85, 0xc5,
11979 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
11980 0x9d, 0x01, 0x36, 0x10,
11981 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
11982 0x98, 0x80, 0xfe, 0x19,
11983 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
11984 0xfe, 0x44, 0x54, 0xbe,
11985 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
11986 0x02, 0x4a, 0x08, 0x05,
11987 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
11988 0x9c, 0x3c, 0xfe, 0x6c,
11989 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
11990 0x3b, 0x40, 0x03, 0x49,
11991 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
11992 0x8f, 0xfe, 0xe3, 0x54,
11993 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
11994 0xda, 0x09, 0xfe, 0x8b,
11995 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
11996 0x0a, 0x3a, 0x49, 0x3b,
11997 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
11998 0xad, 0xfe, 0x01, 0x59,
11999 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
12000 0x49, 0x8f, 0xfe, 0xe3,
12001 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
12002 0x4a, 0x3a, 0x49, 0x3b,
12003 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
12004 0x02, 0x4a, 0x08, 0x05,
12005 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
12006 0xb7, 0xfe, 0x03, 0xa1,
12007 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12008 0xfe, 0x86, 0x91, 0x6a,
12009 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12010 0x61, 0x0c, 0x7f, 0x14,
12011 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12012 0x9b, 0x2e, 0x9c, 0x3c,
12013 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12014 0xfa, 0x3c, 0x01, 0xef,
12015 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12016 0xe4, 0x08, 0x05, 0x1f,
12017 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12018 0x03, 0x5e, 0x29, 0x5f,
12019 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12020 0xf4, 0x09, 0x08, 0x05,
12021 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12022 0x81, 0x50, 0xfe, 0x10,
12023 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12024 0x08, 0x09, 0x12, 0xa6,
12025 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12026 0x08, 0x09, 0xfe, 0x0c,
12027 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12028 0x08, 0x05, 0x0a, 0xfe,
12029 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12030 0xf0, 0xe2, 0x15, 0x7e,
12031 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12032 0x57, 0x3d, 0xfe, 0xed,
12033 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12034 0x00, 0xff, 0x35, 0xfe,
12035 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12036 0x1e, 0x19, 0x8a, 0x03,
12037 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12038 0xfe, 0xd1, 0xf0, 0xfe,
12039 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12040 0x10, 0xfe, 0xce, 0xf0,
12041 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12042 0x10, 0xfe, 0x22, 0x00,
12043 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12044 0x02, 0x65, 0xfe, 0xd0,
12045 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12046 0x0b, 0x10, 0x58, 0xfe,
12047 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12048 0x12, 0x00, 0x2c, 0x0f,
12049 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12050 0x0c, 0xbc, 0x17, 0x34,
12051 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12052 0x0c, 0x1c, 0x34, 0x94,
12053 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12054 0x4b, 0xfe, 0xdb, 0x10,
12055 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12056 0x89, 0xf0, 0x24, 0x33,
12057 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12058 0x33, 0x31, 0xdf, 0xbc,
12059 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12060 0x17, 0xfe, 0x2c, 0x0d,
12061 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12062 0x12, 0x55, 0xfe, 0x28,
12063 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12064 0x44, 0xfe, 0x28, 0x00,
12065 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12066 0x0f, 0x64, 0x12, 0x2f,
12067 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12068 0x0a, 0xfe, 0xb4, 0x10,
12069 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12070 0xfe, 0x34, 0x46, 0xac,
12071 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12072 0x37, 0x01, 0xf5, 0x01,
12073 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12074 0xfe, 0x2e, 0x03, 0x08,
12075 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12076 0x1a, 0xfe, 0x58, 0x12,
12077 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12078 0xfe, 0x50, 0x0d, 0xfe,
12079 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12080 0xfe, 0xa9, 0x10, 0x10,
12081 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12082 0xfe, 0x13, 0x00, 0xfe,
12083 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12084 0x24, 0x00, 0x8c, 0xb5,
12085 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12086 0xfe, 0x9d, 0x41, 0xfe,
12087 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12088 0xb4, 0x15, 0xfe, 0x31,
12089 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12090 0xec, 0xd0, 0xfc, 0x44,
12091 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12092 0x4b, 0x91, 0xfe, 0x75,
12093 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12094 0x0e, 0xfe, 0x44, 0x48,
12095 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12096 0xfe, 0x41, 0x58, 0x09,
12097 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12098 0x2e, 0x03, 0x09, 0x5d,
12099 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12100 0xce, 0x47, 0xfe, 0xad,
12101 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12102 0x59, 0x13, 0x9f, 0x13,
12103 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12104 0xe0, 0x0e, 0x0f, 0x06,
12105 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12106 0x3a, 0x01, 0x56, 0xfe,
12107 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12108 0x20, 0x4f, 0xfe, 0x05,
12109 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12110 0x48, 0xf4, 0x0d, 0xfe,
12111 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12112 0x15, 0x1a, 0x39, 0xa0,
12113 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12114 0x0c, 0xfe, 0x60, 0x01,
12115 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12116 0x06, 0x13, 0x2f, 0x12,
12117 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12118 0x22, 0x9f, 0xb7, 0x13,
12119 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12120 0xa0, 0xb4, 0xfe, 0xd9,
12121 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12122 0xc3, 0xfe, 0x03, 0xdc,
12123 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12124 0xfe, 0x00, 0xcc, 0x04,
12125 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12126 0xfe, 0x1c, 0x80, 0x07,
12127 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12128 0xfe, 0x0c, 0x90, 0xfe,
12129 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12130 0x0a, 0xfe, 0x3c, 0x50,
12131 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12132 0x16, 0x08, 0x05, 0x1b,
12133 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12134 0xfe, 0x2c, 0x13, 0x01,
12135 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12136 0x0c, 0xfe, 0x64, 0x01,
12137 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12138 0x80, 0x8d, 0xfe, 0x01,
12139 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12140 0x22, 0x20, 0xfb, 0x79,
12141 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12142 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012143
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012144 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12145 0xb2, 0x00, 0xfe, 0x09,
12146 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12147 0x45, 0x0f, 0x46, 0x52,
12148 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12149 0x0f, 0x44, 0x11, 0x0f,
12150 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12151 0x25, 0x11, 0x13, 0x20,
12152 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12153 0x56, 0xfe, 0xd6, 0xf0,
12154 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12155 0x18, 0x1c, 0x04, 0x42,
12156 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12157 0xf5, 0x13, 0x04, 0x01,
12158 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12159 0x13, 0x32, 0x07, 0x2f,
12160 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12161 0x41, 0x48, 0xfe, 0x45,
12162 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12163 0x07, 0x11, 0xac, 0x09,
12164 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12165 0x82, 0x4e, 0xfe, 0x14,
12166 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12167 0xfe, 0x01, 0xec, 0xa2,
12168 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12169 0x2a, 0x01, 0xe3, 0xfe,
12170 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12171 0xfe, 0x48, 0x12, 0x07,
12172 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12173 0xfe, 0x32, 0x12, 0x07,
12174 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12175 0x1f, 0xfe, 0x12, 0x12,
12176 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12177 0x94, 0x4b, 0x04, 0x2d,
12178 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12179 0x32, 0x07, 0xa6, 0xfe,
12180 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12181 0x5a, 0xfe, 0x72, 0x12,
12182 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12183 0xfe, 0x26, 0x13, 0x03,
12184 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12185 0x0c, 0x7f, 0x0c, 0x80,
12186 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12187 0x3c, 0xfe, 0x04, 0x55,
12188 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12189 0x91, 0x10, 0x03, 0x3f,
12190 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12191 0x88, 0x9b, 0x2e, 0x9c,
12192 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12193 0x56, 0x0c, 0x5e, 0x14,
12194 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12195 0x03, 0x60, 0x29, 0x61,
12196 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12197 0x50, 0xfe, 0xc6, 0x50,
12198 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12199 0x29, 0x3e, 0xfe, 0x40,
12200 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12201 0x2d, 0x01, 0x0b, 0x1d,
12202 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12203 0x72, 0x01, 0xaf, 0x1e,
12204 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12205 0x0a, 0x55, 0x35, 0xfe,
12206 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12207 0x02, 0x72, 0xfe, 0x19,
12208 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12209 0x1d, 0xe8, 0x33, 0x31,
12210 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12211 0x0b, 0x1c, 0x34, 0x1d,
12212 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12213 0x33, 0x31, 0xfe, 0xe8,
12214 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12215 0x05, 0x1f, 0x35, 0xa9,
12216 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12217 0x14, 0x01, 0xaf, 0x8c,
12218 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12219 0x03, 0x45, 0x28, 0x35,
12220 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12221 0x03, 0x5c, 0xc1, 0x0c,
12222 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12223 0x89, 0x01, 0x0b, 0x1c,
12224 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12225 0xfe, 0x42, 0x58, 0xf1,
12226 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12227 0xf4, 0x06, 0xea, 0x32,
12228 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12229 0x01, 0x0b, 0x26, 0x89,
12230 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12231 0x26, 0xfe, 0xd4, 0x13,
12232 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12233 0x13, 0x1c, 0xfe, 0xd0,
12234 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12235 0x0f, 0x71, 0xff, 0x02,
12236 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12237 0x00, 0x5c, 0x04, 0x0f,
12238 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12239 0xfe, 0x00, 0x5c, 0x04,
12240 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12241 0x02, 0x00, 0x57, 0x52,
12242 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12243 0x87, 0x04, 0xfe, 0x03,
12244 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12245 0xfe, 0x00, 0x7d, 0xfe,
12246 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12247 0x14, 0x5f, 0x57, 0x3f,
12248 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12249 0x5a, 0x8d, 0x04, 0x01,
12250 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12251 0xfe, 0x96, 0x15, 0x33,
12252 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12253 0x0a, 0xfe, 0xc1, 0x59,
12254 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12255 0x21, 0x69, 0x1a, 0xee,
12256 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12257 0x30, 0xfe, 0x78, 0x10,
12258 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12259 0x98, 0xfe, 0x30, 0x00,
12260 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12261 0x98, 0xfe, 0x64, 0x00,
12262 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12263 0x10, 0x69, 0x06, 0xfe,
12264 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12265 0x18, 0x59, 0x0f, 0x06,
12266 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12267 0x43, 0xf4, 0x9f, 0xfe,
12268 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12269 0x9e, 0xfe, 0xf3, 0x10,
12270 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12271 0x17, 0xfe, 0x4d, 0xe4,
12272 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12273 0x17, 0xfe, 0x4d, 0xe4,
12274 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12275 0xf4, 0x00, 0xe9, 0x91,
12276 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12277 0x04, 0x16, 0x06, 0x01,
12278 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12279 0x0b, 0x26, 0xf3, 0x76,
12280 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12281 0x16, 0x19, 0x01, 0x0b,
12282 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12283 0x0b, 0x26, 0xb1, 0x76,
12284 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12285 0xfe, 0x48, 0x13, 0xb8,
12286 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12287 0xec, 0xfe, 0x27, 0x01,
12288 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12289 0x07, 0xfe, 0xe3, 0x00,
12290 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12291 0x22, 0xd4, 0x07, 0x06,
12292 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12293 0x07, 0x11, 0xae, 0x09,
12294 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12295 0x0e, 0x8e, 0xfe, 0x80,
12296 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12297 0x09, 0x48, 0x01, 0x0e,
12298 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12299 0x80, 0xfe, 0x80, 0x4c,
12300 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12301 0x09, 0x5d, 0x01, 0x87,
12302 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12303 0x19, 0xde, 0xfe, 0x24,
12304 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12305 0x17, 0xad, 0x9a, 0x1b,
12306 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12307 0x16, 0xfe, 0xda, 0x10,
12308 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12309 0x18, 0x58, 0x03, 0xfe,
12310 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12311 0xf4, 0x06, 0xfe, 0x3c,
12312 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12313 0x97, 0xfe, 0x38, 0x17,
12314 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12315 0x10, 0x18, 0x11, 0x75,
12316 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12317 0x2e, 0x97, 0xfe, 0x5a,
12318 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12319 0xfe, 0x98, 0xe7, 0x00,
12320 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12321 0xfe, 0x30, 0xbc, 0xfe,
12322 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12323 0xcb, 0x97, 0xfe, 0x92,
12324 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12325 0x42, 0x10, 0xfe, 0x02,
12326 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12327 0x03, 0xa1, 0xfe, 0x1d,
12328 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12329 0x9a, 0x5b, 0x41, 0xfe,
12330 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12331 0x11, 0x12, 0xfe, 0xdd,
12332 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12333 0x17, 0x15, 0x06, 0x39,
12334 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12335 0xfe, 0x7e, 0x18, 0x1e,
12336 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12337 0x12, 0xfe, 0xe1, 0x10,
12338 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12339 0x13, 0x42, 0x92, 0x09,
12340 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12341 0xf0, 0xfe, 0x00, 0xcc,
12342 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12343 0x0e, 0xfe, 0x80, 0x4c,
12344 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12345 0x24, 0x12, 0xfe, 0x14,
12346 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12347 0xe7, 0x0a, 0x10, 0xfe,
12348 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12349 0x08, 0x54, 0x1b, 0x37,
12350 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12351 0x90, 0x3a, 0xce, 0x3b,
12352 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
12353 0x13, 0xa3, 0x04, 0x09,
12354 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
12355 0x44, 0x17, 0xfe, 0xe8,
12356 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
12357 0x5d, 0x01, 0xa8, 0x09,
12358 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
12359 0x1c, 0x19, 0x03, 0xfe,
12360 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
12361 0x6b, 0xfe, 0x2e, 0x19,
12362 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
12363 0xfe, 0x0b, 0x00, 0x6b,
12364 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
12365 0x08, 0x10, 0x03, 0xfe,
12366 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
12367 0x04, 0x68, 0x54, 0xe7,
12368 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
12369 0x1a, 0xf4, 0xfe, 0x00,
12370 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
12371 0x04, 0x07, 0x7e, 0xfe,
12372 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12373 0x07, 0x1a, 0xfe, 0x5a,
12374 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
12375 0x25, 0x6d, 0xe5, 0x07,
12376 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
12377 0xa9, 0xb8, 0x04, 0x15,
12378 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
12379 0x40, 0x5c, 0x04, 0x1c,
12380 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
12381 0xf7, 0xfe, 0x82, 0xf0,
12382 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012383};
12384
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012385static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
12386static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012387
12388/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012389static unsigned char _adv_asc38C1600_buf[] = {
12390 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
12391 0x18, 0xe4, 0x01, 0x00,
12392 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
12393 0x07, 0x17, 0xc0, 0x5f,
12394 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
12395 0x85, 0xf0, 0x86, 0xf0,
12396 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
12397 0x98, 0x57, 0x01, 0xe6,
12398 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
12399 0x38, 0x54, 0x32, 0xf0,
12400 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
12401 0x00, 0xe6, 0xb1, 0xf0,
12402 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
12403 0x06, 0x13, 0x0c, 0x1c,
12404 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
12405 0xb9, 0x54, 0x00, 0x80,
12406 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
12407 0x03, 0xe6, 0x01, 0xea,
12408 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
12409 0x04, 0x13, 0xbb, 0x55,
12410 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
12411 0xbb, 0x00, 0xc0, 0x00,
12412 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
12413 0x4c, 0x1c, 0x4e, 0x1c,
12414 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
12415 0x24, 0x01, 0x3c, 0x01,
12416 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
12417 0x78, 0x01, 0x7c, 0x01,
12418 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
12419 0x6e, 0x1e, 0x02, 0x48,
12420 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
12421 0x03, 0xfc, 0x06, 0x00,
12422 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
12423 0x30, 0x1c, 0x38, 0x1c,
12424 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
12425 0x5d, 0xf0, 0xa7, 0xf0,
12426 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
12427 0x33, 0x00, 0x34, 0x00,
12428 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
12429 0x79, 0x01, 0x3c, 0x09,
12430 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
12431 0x40, 0x16, 0x50, 0x16,
12432 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
12433 0x05, 0xf0, 0x09, 0xf0,
12434 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
12435 0x9c, 0x00, 0xa4, 0x00,
12436 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
12437 0xe9, 0x09, 0x5c, 0x0c,
12438 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
12439 0x42, 0x1d, 0x08, 0x44,
12440 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
12441 0x83, 0x55, 0x83, 0x59,
12442 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
12443 0x4b, 0xf4, 0x04, 0xf8,
12444 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
12445 0xa8, 0x00, 0xaa, 0x00,
12446 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
12447 0x7a, 0x01, 0x82, 0x01,
12448 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
12449 0x68, 0x08, 0x10, 0x0d,
12450 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
12451 0xf3, 0x10, 0x06, 0x12,
12452 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
12453 0xf0, 0x35, 0x05, 0xfe,
12454 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
12455 0xfe, 0x88, 0x01, 0xff,
12456 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12457 0x00, 0xfe, 0x57, 0x24,
12458 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
12459 0x00, 0x00, 0xff, 0x08,
12460 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12461 0xff, 0xff, 0xff, 0x13,
12462 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12463 0xfe, 0x04, 0xf7, 0xe8,
12464 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
12465 0x0d, 0x51, 0x37, 0xfe,
12466 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
12467 0xfe, 0xf8, 0x01, 0xfe,
12468 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
12469 0x05, 0xfe, 0x08, 0x0f,
12470 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
12471 0x28, 0x1c, 0x03, 0xfe,
12472 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
12473 0x48, 0xf0, 0xfe, 0x90,
12474 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
12475 0x02, 0xfe, 0x46, 0xf0,
12476 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
12477 0xfe, 0x4e, 0x02, 0xfe,
12478 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
12479 0x0d, 0xa2, 0x1c, 0x07,
12480 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
12481 0x1c, 0xf5, 0xfe, 0x1e,
12482 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
12483 0xde, 0x0a, 0x81, 0x01,
12484 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
12485 0x81, 0x01, 0x5c, 0xfe,
12486 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
12487 0xfe, 0x58, 0x1c, 0x1c,
12488 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
12489 0x2b, 0xfe, 0x9e, 0x02,
12490 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
12491 0x00, 0x47, 0xb8, 0x01,
12492 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
12493 0x1a, 0x31, 0xfe, 0x69,
12494 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
12495 0x1e, 0x1e, 0x20, 0x2c,
12496 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
12497 0x44, 0x15, 0x56, 0x51,
12498 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
12499 0x01, 0x18, 0x09, 0x00,
12500 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
12501 0x18, 0xfe, 0xc8, 0x54,
12502 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
12503 0xfe, 0x02, 0xe8, 0x30,
12504 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
12505 0xfe, 0xe4, 0x01, 0xfe,
12506 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
12507 0x26, 0xf0, 0xfe, 0x66,
12508 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
12509 0xef, 0x10, 0xfe, 0x9f,
12510 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
12511 0x70, 0x37, 0xfe, 0x48,
12512 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
12513 0x21, 0xb9, 0xc7, 0x20,
12514 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
12515 0xe1, 0x2a, 0xeb, 0xfe,
12516 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
12517 0x15, 0xfe, 0xe4, 0x00,
12518 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
12519 0xfe, 0x06, 0xf0, 0xfe,
12520 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
12521 0x03, 0x81, 0x1e, 0x1b,
12522 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
12523 0xea, 0xfe, 0x46, 0x1c,
12524 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12525 0xfe, 0x48, 0x1c, 0x75,
12526 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
12527 0xe1, 0x01, 0x18, 0x77,
12528 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
12529 0x8f, 0xfe, 0x70, 0x02,
12530 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
12531 0x16, 0xfe, 0x4a, 0x04,
12532 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
12533 0x02, 0x00, 0x10, 0x01,
12534 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
12535 0xee, 0xfe, 0x4c, 0x44,
12536 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
12537 0x7b, 0xec, 0x60, 0x8d,
12538 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
12539 0x0c, 0x06, 0x28, 0xfe,
12540 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
12541 0x13, 0x34, 0xfe, 0x4c,
12542 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
12543 0x13, 0x01, 0x0c, 0x06,
12544 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
12545 0x28, 0xf9, 0x1f, 0x7f,
12546 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
12547 0xfe, 0xa4, 0x0e, 0x05,
12548 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
12549 0x9c, 0x93, 0x3a, 0x0b,
12550 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
12551 0x7d, 0x1d, 0xfe, 0x46,
12552 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
12553 0xfe, 0x87, 0x83, 0xfe,
12554 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
12555 0x13, 0x0f, 0xfe, 0x20,
12556 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
12557 0x12, 0x01, 0x38, 0x06,
12558 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
12559 0x05, 0xd0, 0x54, 0x01,
12560 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
12561 0x50, 0x12, 0x5e, 0xff,
12562 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
12563 0x00, 0x10, 0x2f, 0xfe,
12564 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
12565 0x38, 0xfe, 0x4a, 0xf0,
12566 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
12567 0x21, 0x00, 0xf1, 0x2e,
12568 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
12569 0x10, 0x2f, 0xfe, 0xd0,
12570 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
12571 0x1c, 0x00, 0x4d, 0x01,
12572 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
12573 0x28, 0xfe, 0x24, 0x12,
12574 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
12575 0x0d, 0x00, 0x01, 0x42,
12576 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
12577 0x03, 0xb6, 0x1e, 0xfe,
12578 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
12579 0xfe, 0x72, 0x06, 0x0a,
12580 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
12581 0x19, 0x16, 0xfe, 0x68,
12582 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
12583 0x03, 0x9a, 0x1e, 0xfe,
12584 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
12585 0x48, 0xfe, 0x92, 0x06,
12586 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
12587 0x58, 0xff, 0x02, 0x00,
12588 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
12589 0xfe, 0xea, 0x06, 0x01,
12590 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
12591 0xfe, 0xe0, 0x06, 0x15,
12592 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
12593 0x01, 0x84, 0xfe, 0xae,
12594 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
12595 0x1e, 0xfe, 0x1a, 0x12,
12596 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
12597 0x43, 0x48, 0x62, 0x80,
12598 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
12599 0x36, 0xfe, 0x02, 0xf6,
12600 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
12601 0xd0, 0x0d, 0x17, 0xfe,
12602 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
12603 0x9e, 0x15, 0x82, 0x01,
12604 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
12605 0x57, 0x10, 0xe6, 0x05,
12606 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
12607 0xfe, 0x9c, 0x32, 0x5f,
12608 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
12609 0xfe, 0x0a, 0xf0, 0xfe,
12610 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
12611 0xaf, 0xa0, 0x05, 0x29,
12612 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
12613 0x00, 0x01, 0x08, 0x14,
12614 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
12615 0x14, 0x00, 0x05, 0xfe,
12616 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
12617 0x12, 0xfe, 0x30, 0x13,
12618 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
12619 0x01, 0x08, 0x14, 0x00,
12620 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
12621 0x78, 0x4f, 0x0f, 0xfe,
12622 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
12623 0x28, 0x48, 0xfe, 0x6c,
12624 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
12625 0x12, 0x53, 0x63, 0x4e,
12626 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
12627 0x6c, 0x08, 0xaf, 0xa0,
12628 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
12629 0x05, 0xed, 0xfe, 0x9c,
12630 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
12631 0x1e, 0xfe, 0x99, 0x58,
12632 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
12633 0x22, 0x6b, 0x01, 0x0c,
12634 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
12635 0x1e, 0x47, 0x2c, 0x7a,
12636 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
12637 0x01, 0x0c, 0x61, 0x65,
12638 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
12639 0x16, 0xfe, 0x08, 0x50,
12640 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
12641 0x01, 0xfe, 0xce, 0x1e,
12642 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
12643 0x01, 0xfe, 0xfe, 0x1e,
12644 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
12645 0x10, 0x01, 0x0c, 0x06,
12646 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
12647 0x10, 0x6a, 0x22, 0x6b,
12648 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
12649 0xfe, 0x9f, 0x83, 0x33,
12650 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
12651 0x3a, 0x0b, 0xfe, 0xc6,
12652 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
12653 0x01, 0xfe, 0xce, 0x1e,
12654 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
12655 0x04, 0xfe, 0xc0, 0x93,
12656 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
12657 0x10, 0x4b, 0x22, 0x4c,
12658 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
12659 0x4e, 0x11, 0x2f, 0xfe,
12660 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
12661 0x3c, 0x37, 0x88, 0xf5,
12662 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
12663 0xd3, 0xfe, 0x42, 0x0a,
12664 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
12665 0x05, 0x29, 0x01, 0x41,
12666 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
12667 0xfe, 0x14, 0x12, 0x01,
12668 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
12669 0x2e, 0x1c, 0x05, 0xfe,
12670 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
12671 0xfe, 0x2c, 0x1c, 0xfe,
12672 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
12673 0x92, 0x10, 0xc4, 0xf6,
12674 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
12675 0xe7, 0x10, 0xfe, 0x2b,
12676 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
12677 0xac, 0xfe, 0xd2, 0xf0,
12678 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
12679 0x1b, 0xbf, 0xd4, 0x5b,
12680 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
12681 0x5e, 0x32, 0x1f, 0x7f,
12682 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
12683 0x05, 0x70, 0xfe, 0x74,
12684 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
12685 0x0f, 0x4d, 0x01, 0xfe,
12686 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
12687 0x0d, 0x2b, 0xfe, 0xe2,
12688 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
12689 0xfe, 0x88, 0x13, 0x21,
12690 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
12691 0x83, 0x83, 0xfe, 0xc9,
12692 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
12693 0x91, 0x04, 0xfe, 0x84,
12694 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
12695 0xfe, 0xcb, 0x57, 0x0b,
12696 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
12697 0x6a, 0x3b, 0x6b, 0x10,
12698 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
12699 0x20, 0x6e, 0xdb, 0x64,
12700 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
12701 0xfe, 0x04, 0xfa, 0x64,
12702 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
12703 0x10, 0x98, 0x91, 0x6c,
12704 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
12705 0x4b, 0x7e, 0x4c, 0x01,
12706 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
12707 0x58, 0xfe, 0x91, 0x58,
12708 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
12709 0x1b, 0x40, 0x01, 0x0c,
12710 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
12711 0xfe, 0x10, 0x90, 0x04,
12712 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
12713 0x79, 0x0b, 0x0e, 0xfe,
12714 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
12715 0x01, 0x0c, 0x06, 0x0d,
12716 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
12717 0x0c, 0x58, 0xfe, 0x8d,
12718 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
12719 0x83, 0x33, 0x0b, 0x0e,
12720 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
12721 0x19, 0xfe, 0x19, 0x41,
12722 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
12723 0x19, 0xfe, 0x44, 0x00,
12724 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
12725 0x4c, 0xfe, 0x0c, 0x51,
12726 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
12727 0x76, 0x10, 0xac, 0xfe,
12728 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
12729 0xe3, 0x23, 0x07, 0xfe,
12730 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
12731 0xcc, 0x0c, 0x1f, 0x92,
12732 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
12733 0x0c, 0xfe, 0x3e, 0x10,
12734 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
12735 0xfe, 0xcb, 0xf0, 0xfe,
12736 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
12737 0xf4, 0x0c, 0x19, 0x94,
12738 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
12739 0xfe, 0xcc, 0xf0, 0xef,
12740 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
12741 0x4e, 0x11, 0x2f, 0xfe,
12742 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
12743 0x3c, 0x37, 0x88, 0xf5,
12744 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
12745 0x2f, 0xfe, 0x3e, 0x0d,
12746 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
12747 0xd2, 0x9f, 0xd3, 0x9f,
12748 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
12749 0xc5, 0x75, 0xd7, 0x99,
12750 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
12751 0x9c, 0x2f, 0xfe, 0x8c,
12752 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
12753 0x42, 0x00, 0x05, 0x70,
12754 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
12755 0x0d, 0xfe, 0x44, 0x13,
12756 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
12757 0xfe, 0xda, 0x0e, 0x0a,
12758 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
12759 0x10, 0x01, 0xfe, 0xf4,
12760 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
12761 0x15, 0x56, 0x01, 0x85,
12762 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
12763 0xcc, 0x10, 0x01, 0xa7,
12764 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
12765 0xfe, 0x99, 0x83, 0xfe,
12766 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
12767 0x43, 0x00, 0xfe, 0xa2,
12768 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
12769 0x00, 0x1d, 0x40, 0x15,
12770 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
12771 0xfe, 0x3a, 0x03, 0x01,
12772 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
12773 0x76, 0x06, 0x12, 0xfe,
12774 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
12775 0xfe, 0x9d, 0xf0, 0xfe,
12776 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
12777 0x0c, 0x61, 0x12, 0x44,
12778 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
12779 0xfe, 0x2e, 0x10, 0x19,
12780 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
12781 0xfe, 0x41, 0x00, 0xa2,
12782 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
12783 0xea, 0x4f, 0xfe, 0x04,
12784 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
12785 0x35, 0xfe, 0x12, 0x1c,
12786 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
12787 0xfe, 0xd4, 0x11, 0x05,
12788 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
12789 0xce, 0x45, 0x31, 0x51,
12790 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
12791 0x67, 0xfe, 0x98, 0x56,
12792 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
12793 0x0c, 0x06, 0x28, 0xfe,
12794 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
12795 0xfe, 0xfa, 0x14, 0xfe,
12796 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
12797 0xfe, 0xe0, 0x14, 0xfe,
12798 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
12799 0xfe, 0xad, 0x13, 0x05,
12800 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
12801 0xe7, 0xfe, 0x08, 0x1c,
12802 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
12803 0x48, 0x55, 0xa5, 0x3b,
12804 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
12805 0xf0, 0x1a, 0x03, 0xfe,
12806 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
12807 0xec, 0xe7, 0x53, 0x00,
12808 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
12809 0x01, 0xfe, 0x62, 0x1b,
12810 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
12811 0xea, 0xe7, 0x53, 0x92,
12812 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
12813 0xfe, 0x38, 0x01, 0x23,
12814 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
12815 0x01, 0x01, 0xfe, 0x1e,
12816 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
12817 0x26, 0x02, 0x21, 0x96,
12818 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
12819 0xc3, 0xfe, 0xe1, 0x10,
12820 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
12821 0xfe, 0x03, 0xdc, 0xfe,
12822 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
12823 0x00, 0xcc, 0x02, 0xfe,
12824 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
12825 0x0f, 0xfe, 0x1c, 0x80,
12826 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
12827 0x0f, 0xfe, 0x1e, 0x80,
12828 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
12829 0x1d, 0x80, 0x04, 0xfe,
12830 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
12831 0x1e, 0xac, 0xfe, 0x14,
12832 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
12833 0x1f, 0xfe, 0x30, 0xf4,
12834 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
12835 0x56, 0xfb, 0x01, 0xfe,
12836 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
12837 0xfe, 0x00, 0x1d, 0x15,
12838 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
12839 0x22, 0x1b, 0xfe, 0x1e,
12840 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
12841 0x96, 0x90, 0x04, 0xfe,
12842 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
12843 0x01, 0x01, 0x0c, 0x06,
12844 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
12845 0x0e, 0x77, 0xfe, 0x01,
12846 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
12847 0x21, 0x2c, 0xfe, 0x00,
12848 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
12849 0x06, 0x58, 0x03, 0xfe,
12850 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
12851 0x03, 0xfe, 0xb2, 0x00,
12852 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
12853 0x66, 0x10, 0x55, 0x10,
12854 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
12855 0x54, 0x2b, 0xfe, 0x88,
12856 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
12857 0x91, 0x54, 0x2b, 0xfe,
12858 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
12859 0x00, 0x40, 0x8d, 0x2c,
12860 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
12861 0x12, 0x1c, 0x75, 0xfe,
12862 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
12863 0x14, 0xfe, 0x0e, 0x47,
12864 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
12865 0xa7, 0x90, 0x34, 0x60,
12866 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
12867 0x09, 0x56, 0xfe, 0x34,
12868 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
12869 0xfe, 0x45, 0x48, 0x01,
12870 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
12871 0x09, 0x1a, 0xa5, 0x0a,
12872 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
12873 0xfe, 0x14, 0x56, 0xfe,
12874 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
12875 0xec, 0xb8, 0xfe, 0x9e,
12876 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
12877 0xf4, 0xfe, 0xdd, 0x10,
12878 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
12879 0x12, 0x09, 0x0d, 0xfe,
12880 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
12881 0x13, 0x09, 0xfe, 0x23,
12882 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
12883 0x24, 0xfe, 0x12, 0x12,
12884 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
12885 0xae, 0x41, 0x02, 0x32,
12886 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
12887 0x35, 0x32, 0x01, 0x43,
12888 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
12889 0x13, 0x01, 0x0c, 0x06,
12890 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
12891 0xe5, 0x55, 0xb0, 0xfe,
12892 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
12893 0xfe, 0xb6, 0x0e, 0x10,
12894 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
12895 0x88, 0x20, 0x6e, 0x01,
12896 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
12897 0x55, 0xfe, 0x04, 0xfa,
12898 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
12899 0xfe, 0x40, 0x56, 0xfe,
12900 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
12901 0x44, 0x55, 0xfe, 0xe5,
12902 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
12903 0x68, 0x22, 0x69, 0x01,
12904 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
12905 0x6b, 0xfe, 0x2c, 0x50,
12906 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
12907 0x50, 0x03, 0x68, 0x3b,
12908 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
12909 0x40, 0x50, 0xfe, 0xc2,
12910 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
12911 0x16, 0x3d, 0x27, 0x25,
12912 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
12913 0xa6, 0x23, 0x3f, 0x1b,
12914 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
12915 0xfe, 0x0a, 0x55, 0x31,
12916 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
12917 0x51, 0x05, 0x72, 0x01,
12918 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
12919 0x2a, 0x3c, 0x16, 0xc0,
12920 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
12921 0xfe, 0x66, 0x15, 0x05,
12922 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
12923 0x2b, 0x3d, 0x01, 0x08,
12924 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
12925 0xb6, 0x1e, 0x83, 0x01,
12926 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
12927 0x07, 0x90, 0x3f, 0x01,
12928 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
12929 0x01, 0x43, 0x09, 0x82,
12930 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
12931 0x05, 0x72, 0xfe, 0xc0,
12932 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
12933 0x32, 0x01, 0x08, 0x17,
12934 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
12935 0x3d, 0x27, 0x25, 0xbd,
12936 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
12937 0xe8, 0x14, 0x01, 0xa6,
12938 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
12939 0x0e, 0x12, 0x01, 0x43,
12940 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
12941 0x01, 0x08, 0x17, 0x73,
12942 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
12943 0x27, 0x25, 0xbd, 0x09,
12944 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
12945 0xb6, 0x14, 0x86, 0xa8,
12946 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
12947 0x82, 0x4e, 0x05, 0x72,
12948 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
12949 0xfe, 0xc0, 0x19, 0x05,
12950 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
12951 0xcc, 0x01, 0x08, 0x26,
12952 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
12953 0xcc, 0x15, 0x5e, 0x32,
12954 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
12955 0xad, 0x23, 0xfe, 0xff,
12956 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
12957 0x00, 0x57, 0x52, 0xad,
12958 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
12959 0x02, 0x00, 0x57, 0x52,
12960 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
12961 0x02, 0x13, 0x58, 0xff,
12962 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
12963 0x5c, 0x0a, 0x55, 0x01,
12964 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
12965 0xff, 0x03, 0x00, 0x54,
12966 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
12967 0x7c, 0x3a, 0x0b, 0x0e,
12968 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
12969 0xfe, 0x1a, 0xf7, 0x00,
12970 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
12971 0xda, 0x6d, 0x02, 0xfe,
12972 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
12973 0x02, 0x01, 0xc6, 0xfe,
12974 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
12975 0x25, 0xbe, 0x01, 0x08,
12976 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
12977 0x03, 0x9a, 0x1e, 0xfe,
12978 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
12979 0x48, 0xfe, 0x08, 0x17,
12980 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
12981 0x17, 0x4d, 0x13, 0x07,
12982 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
12983 0xff, 0x02, 0x83, 0x55,
12984 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
12985 0x17, 0x1c, 0x63, 0x13,
12986 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
12987 0x00, 0xb0, 0xfe, 0x80,
12988 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
12989 0x53, 0x07, 0xfe, 0x60,
12990 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
12991 0x00, 0x1c, 0x95, 0x13,
12992 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
12993 0xfe, 0x43, 0xf4, 0x96,
12994 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
12995 0xf4, 0x94, 0xf6, 0x8b,
12996 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
12997 0xda, 0x17, 0x62, 0x49,
12998 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
12999 0x71, 0x50, 0x26, 0xfe,
13000 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
13001 0x58, 0x02, 0x50, 0x13,
13002 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
13003 0x25, 0xbe, 0xfe, 0x03,
13004 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
13005 0x0a, 0x01, 0x08, 0x16,
13006 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13007 0x01, 0x08, 0x16, 0xa9,
13008 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13009 0x08, 0x16, 0xa9, 0x27,
13010 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13011 0x01, 0x38, 0x06, 0x24,
13012 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13013 0x78, 0x03, 0x9a, 0x1e,
13014 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13015 0xfe, 0x40, 0x5a, 0x23,
13016 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13017 0x80, 0x48, 0xfe, 0xaa,
13018 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13019 0xfe, 0xac, 0x1d, 0xfe,
13020 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13021 0x43, 0x48, 0x2d, 0x93,
13022 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13023 0x36, 0xfe, 0x34, 0xf4,
13024 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13025 0x28, 0x10, 0xfe, 0xc0,
13026 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13027 0x18, 0x45, 0xfe, 0x1c,
13028 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13029 0x19, 0xfe, 0x04, 0xf4,
13030 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13031 0x21, 0xfe, 0x7f, 0x01,
13032 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13033 0x7e, 0x01, 0xfe, 0xc8,
13034 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13035 0x21, 0xfe, 0x81, 0x01,
13036 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13037 0x13, 0x0d, 0x02, 0x14,
13038 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13039 0xfe, 0x82, 0x19, 0x14,
13040 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13041 0x08, 0x02, 0x14, 0x07,
13042 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13043 0x01, 0x08, 0x17, 0xc1,
13044 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13045 0x08, 0x02, 0x50, 0x02,
13046 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13047 0x14, 0x12, 0x01, 0x08,
13048 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13049 0x08, 0x17, 0x74, 0xfe,
13050 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13051 0x74, 0x5f, 0xcc, 0x01,
13052 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13053 0xfe, 0x49, 0xf4, 0x00,
13054 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13055 0x02, 0x00, 0x10, 0x2f,
13056 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13057 0x16, 0xfe, 0x64, 0x1a,
13058 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13059 0x61, 0x07, 0x44, 0x02,
13060 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13061 0x13, 0x0a, 0x9d, 0x01,
13062 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13063 0xfe, 0x80, 0xe7, 0x1a,
13064 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13065 0x0a, 0x5a, 0x01, 0x18,
13066 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13067 0x7e, 0x1e, 0xfe, 0x80,
13068 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13069 0xfe, 0x80, 0x4c, 0x0a,
13070 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13071 0xfe, 0x19, 0xde, 0xfe,
13072 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13073 0x2a, 0x1c, 0xfa, 0xb3,
13074 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13075 0xf4, 0x1a, 0xfe, 0xfa,
13076 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13077 0xfe, 0x18, 0x58, 0x03,
13078 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13079 0xfe, 0x30, 0xf4, 0x07,
13080 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13081 0xf7, 0x24, 0xb1, 0xfe,
13082 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13083 0xfe, 0xba, 0x10, 0x1c,
13084 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13085 0x1d, 0xf7, 0x54, 0xb1,
13086 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13087 0xaf, 0x19, 0xfe, 0x98,
13088 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13089 0x1a, 0x87, 0x8b, 0x0f,
13090 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13091 0xfe, 0x32, 0x90, 0x04,
13092 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13093 0x7c, 0x12, 0xfe, 0x0f,
13094 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13095 0x31, 0x02, 0xc9, 0x2b,
13096 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13097 0x6a, 0xfe, 0x19, 0xfe,
13098 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13099 0x1b, 0xfe, 0x36, 0x14,
13100 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13101 0xfe, 0x80, 0xe7, 0x1a,
13102 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13103 0x30, 0xfe, 0x12, 0x45,
13104 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13105 0x39, 0xf0, 0x75, 0x26,
13106 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13107 0xe3, 0x23, 0x07, 0xfe,
13108 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13109 0x56, 0xfe, 0x3c, 0x13,
13110 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13111 0x01, 0x18, 0xcb, 0xfe,
13112 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13113 0xfe, 0x00, 0xcc, 0xcb,
13114 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13115 0xfe, 0x80, 0x4c, 0x01,
13116 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13117 0x12, 0xfe, 0x14, 0x56,
13118 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13119 0x0d, 0x19, 0xfe, 0x15,
13120 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13121 0x83, 0xfe, 0x18, 0x80,
13122 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13123 0x90, 0xfe, 0xba, 0x90,
13124 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13125 0x21, 0xb9, 0x88, 0x20,
13126 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13127 0x18, 0xfe, 0x49, 0x44,
13128 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13129 0x1a, 0xa4, 0x0a, 0x67,
13130 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13131 0x1d, 0x7b, 0xfe, 0x52,
13132 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13133 0x4e, 0xe4, 0xdd, 0x7b,
13134 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13135 0xfe, 0x4e, 0xe4, 0xfe,
13136 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13137 0xfe, 0x08, 0x10, 0x03,
13138 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13139 0x68, 0x54, 0xfe, 0xf1,
13140 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13141 0xfe, 0x1a, 0xf4, 0xfe,
13142 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13143 0x09, 0x92, 0xfe, 0x5a,
13144 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13145 0x5a, 0xf0, 0xfe, 0xc8,
13146 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13147 0x1a, 0x10, 0x09, 0x0d,
13148 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13149 0x1f, 0x93, 0x01, 0x42,
13150 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13151 0xfe, 0x14, 0xf0, 0x08,
13152 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13153 0xfe, 0x82, 0xf0, 0xfe,
13154 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13155 0x02, 0x0f, 0xfe, 0x18,
13156 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13157 0x80, 0x04, 0xfe, 0x82,
13158 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13159 0x83, 0x33, 0x0b, 0x0e,
13160 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13161 0x02, 0x0f, 0xfe, 0x04,
13162 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13163 0x80, 0x04, 0xfe, 0x80,
13164 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13165 0xfe, 0x99, 0x83, 0xfe,
13166 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13167 0x83, 0xfe, 0xce, 0x47,
13168 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13169 0x0b, 0x0e, 0x02, 0x0f,
13170 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13171 0xfe, 0x08, 0x90, 0x04,
13172 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13173 0xfe, 0x8a, 0x93, 0x79,
13174 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13175 0x0b, 0x0e, 0x02, 0x0f,
13176 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13177 0xfe, 0x3c, 0x90, 0x04,
13178 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13179 0x04, 0xfe, 0x83, 0x83,
13180 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013181};
13182
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013183static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13184static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013185
13186/* a_init.c */
13187/*
13188 * EEPROM Configuration.
13189 *
13190 * All drivers should use this structure to set the default EEPROM
13191 * configuration. The BIOS now uses this structure when it is built.
13192 * Additional structure information can be found in a_condor.h where
13193 * the structure is defined.
13194 *
13195 * The *_Field_IsChar structs are needed to correct for endianness.
13196 * These values are read from the board 16 bits at a time directly
13197 * into the structs. Because some fields are char, the values will be
13198 * in the wrong order. The *_Field_IsChar tells when to flip the
13199 * bytes. Data read and written to PCI memory is automatically swapped
13200 * on big-endian platforms so char fields read as words are actually being
13201 * unswapped on big-endian platforms.
13202 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013203static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013204 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13205 0x0000, /* cfg_msw */
13206 0xFFFF, /* disc_enable */
13207 0xFFFF, /* wdtr_able */
13208 0xFFFF, /* sdtr_able */
13209 0xFFFF, /* start_motor */
13210 0xFFFF, /* tagqng_able */
13211 0xFFFF, /* bios_scan */
13212 0, /* scam_tolerant */
13213 7, /* adapter_scsi_id */
13214 0, /* bios_boot_delay */
13215 3, /* scsi_reset_delay */
13216 0, /* bios_id_lun */
13217 0, /* termination */
13218 0, /* reserved1 */
13219 0xFFE7, /* bios_ctrl */
13220 0xFFFF, /* ultra_able */
13221 0, /* reserved2 */
13222 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13223 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13224 0, /* dvc_cntl */
13225 0, /* bug_fix */
13226 0, /* serial_number_word1 */
13227 0, /* serial_number_word2 */
13228 0, /* serial_number_word3 */
13229 0, /* check_sum */
13230 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13231 , /* oem_name[16] */
13232 0, /* dvc_err_code */
13233 0, /* adv_err_code */
13234 0, /* adv_err_addr */
13235 0, /* saved_dvc_err_code */
13236 0, /* saved_adv_err_code */
13237 0, /* saved_adv_err_addr */
13238 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013239};
13240
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013241static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013242 0, /* cfg_lsw */
13243 0, /* cfg_msw */
13244 0, /* -disc_enable */
13245 0, /* wdtr_able */
13246 0, /* sdtr_able */
13247 0, /* start_motor */
13248 0, /* tagqng_able */
13249 0, /* bios_scan */
13250 0, /* scam_tolerant */
13251 1, /* adapter_scsi_id */
13252 1, /* bios_boot_delay */
13253 1, /* scsi_reset_delay */
13254 1, /* bios_id_lun */
13255 1, /* termination */
13256 1, /* reserved1 */
13257 0, /* bios_ctrl */
13258 0, /* ultra_able */
13259 0, /* reserved2 */
13260 1, /* max_host_qng */
13261 1, /* max_dvc_qng */
13262 0, /* dvc_cntl */
13263 0, /* bug_fix */
13264 0, /* serial_number_word1 */
13265 0, /* serial_number_word2 */
13266 0, /* serial_number_word3 */
13267 0, /* check_sum */
13268 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13269 , /* oem_name[16] */
13270 0, /* dvc_err_code */
13271 0, /* adv_err_code */
13272 0, /* adv_err_addr */
13273 0, /* saved_dvc_err_code */
13274 0, /* saved_adv_err_code */
13275 0, /* saved_adv_err_addr */
13276 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013277};
13278
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013279static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013280 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13281 0x0000, /* 01 cfg_msw */
13282 0xFFFF, /* 02 disc_enable */
13283 0xFFFF, /* 03 wdtr_able */
13284 0x4444, /* 04 sdtr_speed1 */
13285 0xFFFF, /* 05 start_motor */
13286 0xFFFF, /* 06 tagqng_able */
13287 0xFFFF, /* 07 bios_scan */
13288 0, /* 08 scam_tolerant */
13289 7, /* 09 adapter_scsi_id */
13290 0, /* bios_boot_delay */
13291 3, /* 10 scsi_reset_delay */
13292 0, /* bios_id_lun */
13293 0, /* 11 termination_se */
13294 0, /* termination_lvd */
13295 0xFFE7, /* 12 bios_ctrl */
13296 0x4444, /* 13 sdtr_speed2 */
13297 0x4444, /* 14 sdtr_speed3 */
13298 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13299 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13300 0, /* 16 dvc_cntl */
13301 0x4444, /* 17 sdtr_speed4 */
13302 0, /* 18 serial_number_word1 */
13303 0, /* 19 serial_number_word2 */
13304 0, /* 20 serial_number_word3 */
13305 0, /* 21 check_sum */
13306 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13307 , /* 22-29 oem_name[16] */
13308 0, /* 30 dvc_err_code */
13309 0, /* 31 adv_err_code */
13310 0, /* 32 adv_err_addr */
13311 0, /* 33 saved_dvc_err_code */
13312 0, /* 34 saved_adv_err_code */
13313 0, /* 35 saved_adv_err_addr */
13314 0, /* 36 reserved */
13315 0, /* 37 reserved */
13316 0, /* 38 reserved */
13317 0, /* 39 reserved */
13318 0, /* 40 reserved */
13319 0, /* 41 reserved */
13320 0, /* 42 reserved */
13321 0, /* 43 reserved */
13322 0, /* 44 reserved */
13323 0, /* 45 reserved */
13324 0, /* 46 reserved */
13325 0, /* 47 reserved */
13326 0, /* 48 reserved */
13327 0, /* 49 reserved */
13328 0, /* 50 reserved */
13329 0, /* 51 reserved */
13330 0, /* 52 reserved */
13331 0, /* 53 reserved */
13332 0, /* 54 reserved */
13333 0, /* 55 reserved */
13334 0, /* 56 cisptr_lsw */
13335 0, /* 57 cisprt_msw */
13336 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13337 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13338 0, /* 60 reserved */
13339 0, /* 61 reserved */
13340 0, /* 62 reserved */
13341 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013342};
13343
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013344static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013345 0, /* 00 cfg_lsw */
13346 0, /* 01 cfg_msw */
13347 0, /* 02 disc_enable */
13348 0, /* 03 wdtr_able */
13349 0, /* 04 sdtr_speed1 */
13350 0, /* 05 start_motor */
13351 0, /* 06 tagqng_able */
13352 0, /* 07 bios_scan */
13353 0, /* 08 scam_tolerant */
13354 1, /* 09 adapter_scsi_id */
13355 1, /* bios_boot_delay */
13356 1, /* 10 scsi_reset_delay */
13357 1, /* bios_id_lun */
13358 1, /* 11 termination_se */
13359 1, /* termination_lvd */
13360 0, /* 12 bios_ctrl */
13361 0, /* 13 sdtr_speed2 */
13362 0, /* 14 sdtr_speed3 */
13363 1, /* 15 max_host_qng */
13364 1, /* max_dvc_qng */
13365 0, /* 16 dvc_cntl */
13366 0, /* 17 sdtr_speed4 */
13367 0, /* 18 serial_number_word1 */
13368 0, /* 19 serial_number_word2 */
13369 0, /* 20 serial_number_word3 */
13370 0, /* 21 check_sum */
13371 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13372 , /* 22-29 oem_name[16] */
13373 0, /* 30 dvc_err_code */
13374 0, /* 31 adv_err_code */
13375 0, /* 32 adv_err_addr */
13376 0, /* 33 saved_dvc_err_code */
13377 0, /* 34 saved_adv_err_code */
13378 0, /* 35 saved_adv_err_addr */
13379 0, /* 36 reserved */
13380 0, /* 37 reserved */
13381 0, /* 38 reserved */
13382 0, /* 39 reserved */
13383 0, /* 40 reserved */
13384 0, /* 41 reserved */
13385 0, /* 42 reserved */
13386 0, /* 43 reserved */
13387 0, /* 44 reserved */
13388 0, /* 45 reserved */
13389 0, /* 46 reserved */
13390 0, /* 47 reserved */
13391 0, /* 48 reserved */
13392 0, /* 49 reserved */
13393 0, /* 50 reserved */
13394 0, /* 51 reserved */
13395 0, /* 52 reserved */
13396 0, /* 53 reserved */
13397 0, /* 54 reserved */
13398 0, /* 55 reserved */
13399 0, /* 56 cisptr_lsw */
13400 0, /* 57 cisprt_msw */
13401 0, /* 58 subsysvid */
13402 0, /* 59 subsysid */
13403 0, /* 60 reserved */
13404 0, /* 61 reserved */
13405 0, /* 62 reserved */
13406 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013407};
13408
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013409static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013410 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13411 0x0000, /* 01 cfg_msw */
13412 0xFFFF, /* 02 disc_enable */
13413 0xFFFF, /* 03 wdtr_able */
13414 0x5555, /* 04 sdtr_speed1 */
13415 0xFFFF, /* 05 start_motor */
13416 0xFFFF, /* 06 tagqng_able */
13417 0xFFFF, /* 07 bios_scan */
13418 0, /* 08 scam_tolerant */
13419 7, /* 09 adapter_scsi_id */
13420 0, /* bios_boot_delay */
13421 3, /* 10 scsi_reset_delay */
13422 0, /* bios_id_lun */
13423 0, /* 11 termination_se */
13424 0, /* termination_lvd */
13425 0xFFE7, /* 12 bios_ctrl */
13426 0x5555, /* 13 sdtr_speed2 */
13427 0x5555, /* 14 sdtr_speed3 */
13428 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13429 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13430 0, /* 16 dvc_cntl */
13431 0x5555, /* 17 sdtr_speed4 */
13432 0, /* 18 serial_number_word1 */
13433 0, /* 19 serial_number_word2 */
13434 0, /* 20 serial_number_word3 */
13435 0, /* 21 check_sum */
13436 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13437 , /* 22-29 oem_name[16] */
13438 0, /* 30 dvc_err_code */
13439 0, /* 31 adv_err_code */
13440 0, /* 32 adv_err_addr */
13441 0, /* 33 saved_dvc_err_code */
13442 0, /* 34 saved_adv_err_code */
13443 0, /* 35 saved_adv_err_addr */
13444 0, /* 36 reserved */
13445 0, /* 37 reserved */
13446 0, /* 38 reserved */
13447 0, /* 39 reserved */
13448 0, /* 40 reserved */
13449 0, /* 41 reserved */
13450 0, /* 42 reserved */
13451 0, /* 43 reserved */
13452 0, /* 44 reserved */
13453 0, /* 45 reserved */
13454 0, /* 46 reserved */
13455 0, /* 47 reserved */
13456 0, /* 48 reserved */
13457 0, /* 49 reserved */
13458 0, /* 50 reserved */
13459 0, /* 51 reserved */
13460 0, /* 52 reserved */
13461 0, /* 53 reserved */
13462 0, /* 54 reserved */
13463 0, /* 55 reserved */
13464 0, /* 56 cisptr_lsw */
13465 0, /* 57 cisprt_msw */
13466 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13467 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
13468 0, /* 60 reserved */
13469 0, /* 61 reserved */
13470 0, /* 62 reserved */
13471 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013472};
13473
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013474static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013475 0, /* 00 cfg_lsw */
13476 0, /* 01 cfg_msw */
13477 0, /* 02 disc_enable */
13478 0, /* 03 wdtr_able */
13479 0, /* 04 sdtr_speed1 */
13480 0, /* 05 start_motor */
13481 0, /* 06 tagqng_able */
13482 0, /* 07 bios_scan */
13483 0, /* 08 scam_tolerant */
13484 1, /* 09 adapter_scsi_id */
13485 1, /* bios_boot_delay */
13486 1, /* 10 scsi_reset_delay */
13487 1, /* bios_id_lun */
13488 1, /* 11 termination_se */
13489 1, /* termination_lvd */
13490 0, /* 12 bios_ctrl */
13491 0, /* 13 sdtr_speed2 */
13492 0, /* 14 sdtr_speed3 */
13493 1, /* 15 max_host_qng */
13494 1, /* max_dvc_qng */
13495 0, /* 16 dvc_cntl */
13496 0, /* 17 sdtr_speed4 */
13497 0, /* 18 serial_number_word1 */
13498 0, /* 19 serial_number_word2 */
13499 0, /* 20 serial_number_word3 */
13500 0, /* 21 check_sum */
13501 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13502 , /* 22-29 oem_name[16] */
13503 0, /* 30 dvc_err_code */
13504 0, /* 31 adv_err_code */
13505 0, /* 32 adv_err_addr */
13506 0, /* 33 saved_dvc_err_code */
13507 0, /* 34 saved_adv_err_code */
13508 0, /* 35 saved_adv_err_addr */
13509 0, /* 36 reserved */
13510 0, /* 37 reserved */
13511 0, /* 38 reserved */
13512 0, /* 39 reserved */
13513 0, /* 40 reserved */
13514 0, /* 41 reserved */
13515 0, /* 42 reserved */
13516 0, /* 43 reserved */
13517 0, /* 44 reserved */
13518 0, /* 45 reserved */
13519 0, /* 46 reserved */
13520 0, /* 47 reserved */
13521 0, /* 48 reserved */
13522 0, /* 49 reserved */
13523 0, /* 50 reserved */
13524 0, /* 51 reserved */
13525 0, /* 52 reserved */
13526 0, /* 53 reserved */
13527 0, /* 54 reserved */
13528 0, /* 55 reserved */
13529 0, /* 56 cisptr_lsw */
13530 0, /* 57 cisprt_msw */
13531 0, /* 58 subsysvid */
13532 0, /* 59 subsysid */
13533 0, /* 60 reserved */
13534 0, /* 61 reserved */
13535 0, /* 62 reserved */
13536 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013537};
13538
13539/*
13540 * Initialize the ADV_DVC_VAR structure.
13541 *
13542 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13543 *
13544 * For a non-fatal error return a warning code. If there are no warnings
13545 * then 0 is returned.
13546 */
Matthew Wilcox394dbf32007-07-26 11:56:40 -040013547static int __devinit
13548AdvInitGetConfig(struct pci_dev *pdev, ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013549{
Matthew Wilcox9649af32007-07-26 21:51:47 -060013550 unsigned short warn_code = 0;
13551 AdvPortAddr iop_base = asc_dvc->iop_base;
Matthew Wilcox9649af32007-07-26 21:51:47 -060013552 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013553 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013554
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013555 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013556
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013557 /*
13558 * Save the state of the PCI Configuration Command Register
13559 * "Parity Error Response Control" Bit. If the bit is clear (0),
13560 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
13561 * DMA parity errors.
13562 */
13563 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060013564 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
13565 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013566 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013567
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013568 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
13569 ADV_LIB_VERSION_MINOR;
13570 asc_dvc->cfg->chip_version =
13571 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013572
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013573 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
13574 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
13575 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013577 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
13578 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
13579 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013580
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013581 /*
13582 * Reset the chip to start and allow register writes.
13583 */
13584 if (AdvFindSignature(iop_base) == 0) {
13585 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
13586 return ADV_ERROR;
13587 } else {
13588 /*
13589 * The caller must set 'chip_type' to a valid setting.
13590 */
13591 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
13592 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
13593 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
13594 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13595 return ADV_ERROR;
13596 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013597
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013598 /*
13599 * Reset Chip.
13600 */
13601 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13602 ADV_CTRL_REG_CMD_RESET);
13603 DvcSleepMilliSecond(100);
13604 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13605 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013606
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013607 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013608 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013609 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013610 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013611 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013612 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013613 }
13614 warn_code |= status;
13615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013616
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013617 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013618}
13619
13620/*
13621 * Initialize the ASC-3550.
13622 *
13623 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13624 *
13625 * For a non-fatal error return a warning code. If there are no warnings
13626 * then 0 is returned.
13627 *
13628 * Needed after initialization for error recovery.
13629 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013630static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013631{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013632 AdvPortAddr iop_base;
13633 ushort warn_code;
13634 ADV_DCNT sum;
13635 int begin_addr;
13636 int end_addr;
13637 ushort code_sum;
13638 int word;
13639 int j;
13640 int adv_asc3550_expanded_size;
13641 ADV_CARR_T *carrp;
13642 ADV_DCNT contig_len;
13643 ADV_SDCNT buf_size;
13644 ADV_PADDR carr_paddr;
13645 int i;
13646 ushort scsi_cfg1;
13647 uchar tid;
13648 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
13649 ushort wdtr_able = 0, sdtr_able, tagqng_able;
13650 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013651
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013652 /* If there is already an error, don't continue. */
13653 if (asc_dvc->err_code != 0) {
13654 return ADV_ERROR;
13655 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013657 /*
13658 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
13659 */
13660 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
13661 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13662 return ADV_ERROR;
13663 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013664
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013665 warn_code = 0;
13666 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013667
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013668 /*
13669 * Save the RISC memory BIOS region before writing the microcode.
13670 * The BIOS may already be loaded and using its RISC LRAM region
13671 * so its region must be saved and restored.
13672 *
13673 * Note: This code makes the assumption, which is currently true,
13674 * that a chip reset does not clear RISC LRAM.
13675 */
13676 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13677 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13678 bios_mem[i]);
13679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013680
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013681 /*
13682 * Save current per TID negotiated values.
13683 */
13684 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
13685 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013686
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013687 bios_version =
13688 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
13689 major = (bios_version >> 12) & 0xF;
13690 minor = (bios_version >> 8) & 0xF;
13691 if (major < 3 || (major == 3 && minor == 1)) {
13692 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
13693 AdvReadWordLram(iop_base, 0x120, wdtr_able);
13694 } else {
13695 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13696 }
13697 }
13698 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13699 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13700 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13701 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13702 max_cmd[tid]);
13703 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013704
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013705 /*
13706 * Load the Microcode
13707 *
13708 * Write the microcode image to RISC memory starting at address 0.
13709 */
13710 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
13711 /* Assume the following compressed format of the microcode buffer:
13712 *
13713 * 254 word (508 byte) table indexed by byte code followed
13714 * by the following byte codes:
13715 *
13716 * 1-Byte Code:
13717 * 00: Emit word 0 in table.
13718 * 01: Emit word 1 in table.
13719 * .
13720 * FD: Emit word 253 in table.
13721 *
13722 * Multi-Byte Code:
13723 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
13724 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
13725 */
13726 word = 0;
13727 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
13728 if (_adv_asc3550_buf[i] == 0xff) {
13729 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
13730 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13731 _adv_asc3550_buf
13732 [i +
13733 3] << 8) |
13734 _adv_asc3550_buf
13735 [i + 2]));
13736 word++;
13737 }
13738 i += 3;
13739 } else if (_adv_asc3550_buf[i] == 0xfe) {
13740 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13741 _adv_asc3550_buf[i +
13742 2]
13743 << 8) |
13744 _adv_asc3550_buf[i +
13745 1]));
13746 i += 2;
13747 word++;
13748 } else {
13749 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13750 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
13751 word++;
13752 }
13753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013754
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013755 /*
13756 * Set 'word' for later use to clear the rest of memory and save
13757 * the expanded mcode size.
13758 */
13759 word *= 2;
13760 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013761
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013762 /*
13763 * Clear the rest of ASC-3550 Internal RAM (8KB).
13764 */
13765 for (; word < ADV_3550_MEMSIZE; word += 2) {
13766 AdvWriteWordAutoIncLram(iop_base, 0);
13767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013768
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013769 /*
13770 * Verify the microcode checksum.
13771 */
13772 sum = 0;
13773 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013774
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013775 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
13776 sum += AdvReadWordAutoIncLram(iop_base);
13777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013778
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013779 if (sum != _adv_asc3550_chksum) {
13780 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
13781 return ADV_ERROR;
13782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013783
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013784 /*
13785 * Restore the RISC memory BIOS region.
13786 */
13787 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13788 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13789 bios_mem[i]);
13790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013791
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013792 /*
13793 * Calculate and write the microcode code checksum to the microcode
13794 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
13795 */
13796 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
13797 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
13798 code_sum = 0;
13799 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
13800 for (word = begin_addr; word < end_addr; word += 2) {
13801 code_sum += AdvReadWordAutoIncLram(iop_base);
13802 }
13803 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013804
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013805 /*
13806 * Read and save microcode version and date.
13807 */
13808 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
13809 asc_dvc->cfg->mcode_date);
13810 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
13811 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013812
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013813 /*
13814 * Set the chip type to indicate the ASC3550.
13815 */
13816 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013817
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013818 /*
13819 * If the PCI Configuration Command Register "Parity Error Response
13820 * Control" Bit was clear (0), then set the microcode variable
13821 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
13822 * to ignore DMA parity errors.
13823 */
13824 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
13825 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13826 word |= CONTROL_FLAG_IGNORE_PERR;
13827 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13828 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013829
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013830 /*
13831 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
13832 * threshold of 128 bytes. This register is only accessible to the host.
13833 */
13834 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
13835 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013837 /*
13838 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040013839 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013840 * device reports it is capable of in Inquiry byte 7.
13841 *
13842 * If SCSI Bus Resets have been disabled, then directly set
13843 * SDTR and WDTR from the EEPROM configuration. This will allow
13844 * the BIOS and warm boot to work without a SCSI bus hang on
13845 * the Inquiry caused by host and target mismatched DTR values.
13846 * Without the SCSI Bus Reset, before an Inquiry a device can't
13847 * be assumed to be in Asynchronous, Narrow mode.
13848 */
13849 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
13850 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
13851 asc_dvc->wdtr_able);
13852 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
13853 asc_dvc->sdtr_able);
13854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013855
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013856 /*
13857 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
13858 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
13859 * bitmask. These values determine the maximum SDTR speed negotiated
13860 * with a device.
13861 *
13862 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
13863 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
13864 * without determining here whether the device supports SDTR.
13865 *
13866 * 4-bit speed SDTR speed name
13867 * =========== ===============
13868 * 0000b (0x0) SDTR disabled
13869 * 0001b (0x1) 5 Mhz
13870 * 0010b (0x2) 10 Mhz
13871 * 0011b (0x3) 20 Mhz (Ultra)
13872 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
13873 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
13874 * 0110b (0x6) Undefined
13875 * .
13876 * 1111b (0xF) Undefined
13877 */
13878 word = 0;
13879 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13880 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
13881 /* Set Ultra speed for TID 'tid'. */
13882 word |= (0x3 << (4 * (tid % 4)));
13883 } else {
13884 /* Set Fast speed for TID 'tid'. */
13885 word |= (0x2 << (4 * (tid % 4)));
13886 }
13887 if (tid == 3) { /* Check if done with sdtr_speed1. */
13888 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
13889 word = 0;
13890 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
13891 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
13892 word = 0;
13893 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
13894 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
13895 word = 0;
13896 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
13897 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
13898 /* End of loop. */
13899 }
13900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013901
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013902 /*
13903 * Set microcode operating variable for the disconnect per TID bitmask.
13904 */
13905 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
13906 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013907
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013908 /*
13909 * Set SCSI_CFG0 Microcode Default Value.
13910 *
13911 * The microcode will set the SCSI_CFG0 register using this value
13912 * after it is started below.
13913 */
13914 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
13915 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
13916 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013917
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013918 /*
13919 * Determine SCSI_CFG1 Microcode Default Value.
13920 *
13921 * The microcode will set the SCSI_CFG1 register using this value
13922 * after it is started below.
13923 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013924
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013925 /* Read current SCSI_CFG1 Register value. */
13926 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013927
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013928 /*
13929 * If all three connectors are in use, return an error.
13930 */
13931 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
13932 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
13933 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
13934 return ADV_ERROR;
13935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013936
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013937 /*
13938 * If the internal narrow cable is reversed all of the SCSI_CTRL
13939 * register signals will be set. Check for and return an error if
13940 * this condition is found.
13941 */
13942 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
13943 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
13944 return ADV_ERROR;
13945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013946
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013947 /*
13948 * If this is a differential board and a single-ended device
13949 * is attached to one of the connectors, return an error.
13950 */
13951 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
13952 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
13953 return ADV_ERROR;
13954 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013955
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013956 /*
13957 * If automatic termination control is enabled, then set the
13958 * termination value based on a table listed in a_condor.h.
13959 *
13960 * If manual termination was specified with an EEPROM setting
13961 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
13962 * is ready to be 'ored' into SCSI_CFG1.
13963 */
13964 if (asc_dvc->cfg->termination == 0) {
13965 /*
13966 * The software always controls termination by setting TERM_CTL_SEL.
13967 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
13968 */
13969 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013970
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013971 switch (scsi_cfg1 & CABLE_DETECT) {
13972 /* TERM_CTL_H: on, TERM_CTL_L: on */
13973 case 0x3:
13974 case 0x7:
13975 case 0xB:
13976 case 0xD:
13977 case 0xE:
13978 case 0xF:
13979 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
13980 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013981
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013982 /* TERM_CTL_H: on, TERM_CTL_L: off */
13983 case 0x1:
13984 case 0x5:
13985 case 0x9:
13986 case 0xA:
13987 case 0xC:
13988 asc_dvc->cfg->termination |= TERM_CTL_H;
13989 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013990
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013991 /* TERM_CTL_H: off, TERM_CTL_L: off */
13992 case 0x2:
13993 case 0x6:
13994 break;
13995 }
13996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013997
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013998 /*
13999 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
14000 */
14001 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014002
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014003 /*
14004 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
14005 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
14006 * referenced, because the hardware internally inverts
14007 * the Termination High and Low bits if TERM_POL is set.
14008 */
14009 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014011 /*
14012 * Set SCSI_CFG1 Microcode Default Value
14013 *
14014 * Set filter value and possibly modified termination control
14015 * bits in the Microcode SCSI_CFG1 Register Value.
14016 *
14017 * The microcode will set the SCSI_CFG1 register using this value
14018 * after it is started below.
14019 */
14020 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14021 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014022
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014023 /*
14024 * Set MEM_CFG Microcode Default Value
14025 *
14026 * The microcode will set the MEM_CFG register using this value
14027 * after it is started below.
14028 *
14029 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14030 * are defined.
14031 *
14032 * ASC-3550 has 8KB internal memory.
14033 */
14034 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14035 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014036
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014037 /*
14038 * Set SEL_MASK Microcode Default Value
14039 *
14040 * The microcode will set the SEL_MASK register using this value
14041 * after it is started below.
14042 */
14043 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14044 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014045
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014046 /*
14047 * Build carrier freelist.
14048 *
14049 * Driver must have already allocated memory and set 'carrier_buf'.
14050 */
14051 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014052
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014053 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14054 asc_dvc->carr_freelist = NULL;
14055 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14056 buf_size = ADV_CARRIER_BUFSIZE;
14057 } else {
14058 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14059 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014060
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014061 do {
14062 /*
14063 * Get physical address of the carrier 'carrp'.
14064 */
14065 contig_len = sizeof(ADV_CARR_T);
14066 carr_paddr =
14067 cpu_to_le32(DvcGetPhyAddr
14068 (asc_dvc, NULL, (uchar *)carrp,
14069 (ADV_SDCNT *)&contig_len,
14070 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014071
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014072 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014073
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014074 /*
14075 * If the current carrier is not physically contiguous, then
14076 * maybe there was a page crossing. Try the next carrier aligned
14077 * start address.
14078 */
14079 if (contig_len < sizeof(ADV_CARR_T)) {
14080 carrp++;
14081 continue;
14082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014083
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014084 carrp->carr_pa = carr_paddr;
14085 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014086
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014087 /*
14088 * Insert the carrier at the beginning of the freelist.
14089 */
14090 carrp->next_vpa =
14091 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14092 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014093
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014094 carrp++;
14095 }
14096 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014097
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014098 /*
14099 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014101
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014102 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14103 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14104 return ADV_ERROR;
14105 }
14106 asc_dvc->carr_freelist = (ADV_CARR_T *)
14107 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014108
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014109 /*
14110 * The first command issued will be placed in the stopper carrier.
14111 */
14112 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014113
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014114 /*
14115 * Set RISC ICQ physical address start value.
14116 */
14117 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014118
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014119 /*
14120 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14121 */
14122 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14123 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14124 return ADV_ERROR;
14125 }
14126 asc_dvc->carr_freelist = (ADV_CARR_T *)
14127 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014128
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014129 /*
14130 * The first command completed by the RISC will be placed in
14131 * the stopper.
14132 *
14133 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14134 * completed the RISC will set the ASC_RQ_STOPPER bit.
14135 */
14136 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014137
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014138 /*
14139 * Set RISC IRQ physical address start value.
14140 */
14141 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14142 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014143
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014144 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14145 (ADV_INTR_ENABLE_HOST_INTR |
14146 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014147
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014148 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14149 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014150
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014151 /* finally, finally, gentlemen, start your engine */
14152 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014153
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014154 /*
14155 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14156 * Resets should be performed. The RISC has to be running
14157 * to issue a SCSI Bus Reset.
14158 */
14159 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14160 /*
14161 * If the BIOS Signature is present in memory, restore the
14162 * BIOS Handshake Configuration Table and do not perform
14163 * a SCSI Bus Reset.
14164 */
14165 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14166 0x55AA) {
14167 /*
14168 * Restore per TID negotiated values.
14169 */
14170 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14171 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14172 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14173 tagqng_able);
14174 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14175 AdvWriteByteLram(iop_base,
14176 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14177 max_cmd[tid]);
14178 }
14179 } else {
14180 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14181 warn_code = ASC_WARN_BUSRESET_ERROR;
14182 }
14183 }
14184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014185
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014186 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014187}
14188
14189/*
14190 * Initialize the ASC-38C0800.
14191 *
14192 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14193 *
14194 * For a non-fatal error return a warning code. If there are no warnings
14195 * then 0 is returned.
14196 *
14197 * Needed after initialization for error recovery.
14198 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014199static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014200{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014201 AdvPortAddr iop_base;
14202 ushort warn_code;
14203 ADV_DCNT sum;
14204 int begin_addr;
14205 int end_addr;
14206 ushort code_sum;
14207 int word;
14208 int j;
14209 int adv_asc38C0800_expanded_size;
14210 ADV_CARR_T *carrp;
14211 ADV_DCNT contig_len;
14212 ADV_SDCNT buf_size;
14213 ADV_PADDR carr_paddr;
14214 int i;
14215 ushort scsi_cfg1;
14216 uchar byte;
14217 uchar tid;
14218 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14219 ushort wdtr_able, sdtr_able, tagqng_able;
14220 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014221
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014222 /* If there is already an error, don't continue. */
14223 if (asc_dvc->err_code != 0) {
14224 return ADV_ERROR;
14225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014226
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014227 /*
14228 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14229 */
14230 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14231 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14232 return ADV_ERROR;
14233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014234
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014235 warn_code = 0;
14236 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014237
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014238 /*
14239 * Save the RISC memory BIOS region before writing the microcode.
14240 * The BIOS may already be loaded and using its RISC LRAM region
14241 * so its region must be saved and restored.
14242 *
14243 * Note: This code makes the assumption, which is currently true,
14244 * that a chip reset does not clear RISC LRAM.
14245 */
14246 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14247 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14248 bios_mem[i]);
14249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014250
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014251 /*
14252 * Save current per TID negotiated values.
14253 */
14254 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14255 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14256 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14257 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14258 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14259 max_cmd[tid]);
14260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014261
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014262 /*
14263 * RAM BIST (RAM Built-In Self Test)
14264 *
14265 * Address : I/O base + offset 0x38h register (byte).
14266 * Function: Bit 7-6(RW) : RAM mode
14267 * Normal Mode : 0x00
14268 * Pre-test Mode : 0x40
14269 * RAM Test Mode : 0x80
14270 * Bit 5 : unused
14271 * Bit 4(RO) : Done bit
14272 * Bit 3-0(RO) : Status
14273 * Host Error : 0x08
14274 * Int_RAM Error : 0x04
14275 * RISC Error : 0x02
14276 * SCSI Error : 0x01
14277 * No Error : 0x00
14278 *
14279 * Note: RAM BIST code should be put right here, before loading the
14280 * microcode and after saving the RISC memory BIOS region.
14281 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014283 /*
14284 * LRAM Pre-test
14285 *
14286 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14287 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14288 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14289 * to NORMAL_MODE, return an error too.
14290 */
14291 for (i = 0; i < 2; i++) {
14292 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14293 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14294 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14295 if ((byte & RAM_TEST_DONE) == 0
14296 || (byte & 0x0F) != PRE_TEST_VALUE) {
14297 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14298 return ADV_ERROR;
14299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014300
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014301 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14302 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14303 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14304 != NORMAL_VALUE) {
14305 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14306 return ADV_ERROR;
14307 }
14308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014309
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014310 /*
14311 * LRAM Test - It takes about 1.5 ms to run through the test.
14312 *
14313 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14314 * If Done bit not set or Status not 0, save register byte, set the
14315 * err_code, and return an error.
14316 */
14317 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14318 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014319
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014320 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14321 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14322 /* Get here if Done bit not set or Status not 0. */
14323 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14324 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14325 return ADV_ERROR;
14326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014327
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014328 /* We need to reset back to normal mode after LRAM test passes. */
14329 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014330
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014331 /*
14332 * Load the Microcode
14333 *
14334 * Write the microcode image to RISC memory starting at address 0.
14335 *
14336 */
14337 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014338
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014339 /* Assume the following compressed format of the microcode buffer:
14340 *
14341 * 254 word (508 byte) table indexed by byte code followed
14342 * by the following byte codes:
14343 *
14344 * 1-Byte Code:
14345 * 00: Emit word 0 in table.
14346 * 01: Emit word 1 in table.
14347 * .
14348 * FD: Emit word 253 in table.
14349 *
14350 * Multi-Byte Code:
14351 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14352 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14353 */
14354 word = 0;
14355 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
14356 if (_adv_asc38C0800_buf[i] == 0xff) {
14357 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
14358 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14359 _adv_asc38C0800_buf
14360 [i +
14361 3] << 8) |
14362 _adv_asc38C0800_buf
14363 [i + 2]));
14364 word++;
14365 }
14366 i += 3;
14367 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
14368 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14369 _adv_asc38C0800_buf
14370 [i +
14371 2] << 8) |
14372 _adv_asc38C0800_buf[i
14373 +
14374 1]));
14375 i += 2;
14376 word++;
14377 } else {
14378 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14379 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
14380 word++;
14381 }
14382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014383
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014384 /*
14385 * Set 'word' for later use to clear the rest of memory and save
14386 * the expanded mcode size.
14387 */
14388 word *= 2;
14389 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014390
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014391 /*
14392 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
14393 */
14394 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
14395 AdvWriteWordAutoIncLram(iop_base, 0);
14396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014397
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014398 /*
14399 * Verify the microcode checksum.
14400 */
14401 sum = 0;
14402 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014403
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014404 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
14405 sum += AdvReadWordAutoIncLram(iop_base);
14406 }
14407 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014408
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014409 ASC_DBG2(1,
14410 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
14411 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014412
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014413 if (sum != _adv_asc38C0800_chksum) {
14414 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14415 return ADV_ERROR;
14416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014417
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014418 /*
14419 * Restore the RISC memory BIOS region.
14420 */
14421 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14422 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14423 bios_mem[i]);
14424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014425
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014426 /*
14427 * Calculate and write the microcode code checksum to the microcode
14428 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14429 */
14430 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14431 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14432 code_sum = 0;
14433 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14434 for (word = begin_addr; word < end_addr; word += 2) {
14435 code_sum += AdvReadWordAutoIncLram(iop_base);
14436 }
14437 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014438
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014439 /*
14440 * Read microcode version and date.
14441 */
14442 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14443 asc_dvc->cfg->mcode_date);
14444 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14445 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014446
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014447 /*
14448 * Set the chip type to indicate the ASC38C0800.
14449 */
14450 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014451
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014452 /*
14453 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
14454 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
14455 * cable detection and then we are able to read C_DET[3:0].
14456 *
14457 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
14458 * Microcode Default Value' section below.
14459 */
14460 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
14461 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
14462 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014463
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014464 /*
14465 * If the PCI Configuration Command Register "Parity Error Response
14466 * Control" Bit was clear (0), then set the microcode variable
14467 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14468 * to ignore DMA parity errors.
14469 */
14470 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14471 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14472 word |= CONTROL_FLAG_IGNORE_PERR;
14473 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014475
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014476 /*
14477 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
14478 * bits for the default FIFO threshold.
14479 *
14480 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
14481 *
14482 * For DMA Errata #4 set the BC_THRESH_ENB bit.
14483 */
14484 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14485 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
14486 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014487
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014488 /*
14489 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040014490 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014491 * device reports it is capable of in Inquiry byte 7.
14492 *
14493 * If SCSI Bus Resets have been disabled, then directly set
14494 * SDTR and WDTR from the EEPROM configuration. This will allow
14495 * the BIOS and warm boot to work without a SCSI bus hang on
14496 * the Inquiry caused by host and target mismatched DTR values.
14497 * Without the SCSI Bus Reset, before an Inquiry a device can't
14498 * be assumed to be in Asynchronous, Narrow mode.
14499 */
14500 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14501 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14502 asc_dvc->wdtr_able);
14503 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14504 asc_dvc->sdtr_able);
14505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014506
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014507 /*
14508 * Set microcode operating variables for DISC and SDTR_SPEED1,
14509 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
14510 * configuration values.
14511 *
14512 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14513 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14514 * without determining here whether the device supports SDTR.
14515 */
14516 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14517 asc_dvc->cfg->disc_enable);
14518 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
14519 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
14520 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
14521 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014522
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014523 /*
14524 * Set SCSI_CFG0 Microcode Default Value.
14525 *
14526 * The microcode will set the SCSI_CFG0 register using this value
14527 * after it is started below.
14528 */
14529 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14530 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14531 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014532
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014533 /*
14534 * Determine SCSI_CFG1 Microcode Default Value.
14535 *
14536 * The microcode will set the SCSI_CFG1 register using this value
14537 * after it is started below.
14538 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014539
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014540 /* Read current SCSI_CFG1 Register value. */
14541 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014542
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014543 /*
14544 * If the internal narrow cable is reversed all of the SCSI_CTRL
14545 * register signals will be set. Check for and return an error if
14546 * this condition is found.
14547 */
14548 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14549 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14550 return ADV_ERROR;
14551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014552
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014553 /*
14554 * All kind of combinations of devices attached to one of four connectors
14555 * are acceptable except HVD device attached. For example, LVD device can
14556 * be attached to SE connector while SE device attached to LVD connector.
14557 * If LVD device attached to SE connector, it only runs up to Ultra speed.
14558 *
14559 * If an HVD device is attached to one of LVD connectors, return an error.
14560 * However, there is no way to detect HVD device attached to SE connectors.
14561 */
14562 if (scsi_cfg1 & HVD) {
14563 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
14564 return ADV_ERROR;
14565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014566
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014567 /*
14568 * If either SE or LVD automatic termination control is enabled, then
14569 * set the termination value based on a table listed in a_condor.h.
14570 *
14571 * If manual termination was specified with an EEPROM setting then
14572 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
14573 * be 'ored' into SCSI_CFG1.
14574 */
14575 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
14576 /* SE automatic termination control is enabled. */
14577 switch (scsi_cfg1 & C_DET_SE) {
14578 /* TERM_SE_HI: on, TERM_SE_LO: on */
14579 case 0x1:
14580 case 0x2:
14581 case 0x3:
14582 asc_dvc->cfg->termination |= TERM_SE;
14583 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014584
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014585 /* TERM_SE_HI: on, TERM_SE_LO: off */
14586 case 0x0:
14587 asc_dvc->cfg->termination |= TERM_SE_HI;
14588 break;
14589 }
14590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014591
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014592 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
14593 /* LVD automatic termination control is enabled. */
14594 switch (scsi_cfg1 & C_DET_LVD) {
14595 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
14596 case 0x4:
14597 case 0x8:
14598 case 0xC:
14599 asc_dvc->cfg->termination |= TERM_LVD;
14600 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014601
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014602 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
14603 case 0x0:
14604 break;
14605 }
14606 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014607
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014608 /*
14609 * Clear any set TERM_SE and TERM_LVD bits.
14610 */
14611 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014612
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014613 /*
14614 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
14615 */
14616 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014617
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014618 /*
14619 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
14620 * and set possibly modified termination control bits in the Microcode
14621 * SCSI_CFG1 Register Value.
14622 */
14623 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014624
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014625 /*
14626 * Set SCSI_CFG1 Microcode Default Value
14627 *
14628 * Set possibly modified termination control and reset DIS_TERM_DRV
14629 * bits in the Microcode SCSI_CFG1 Register Value.
14630 *
14631 * The microcode will set the SCSI_CFG1 register using this value
14632 * after it is started below.
14633 */
14634 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014635
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014636 /*
14637 * Set MEM_CFG Microcode Default Value
14638 *
14639 * The microcode will set the MEM_CFG register using this value
14640 * after it is started below.
14641 *
14642 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14643 * are defined.
14644 *
14645 * ASC-38C0800 has 16KB internal memory.
14646 */
14647 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14648 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014649
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014650 /*
14651 * Set SEL_MASK Microcode Default Value
14652 *
14653 * The microcode will set the SEL_MASK register using this value
14654 * after it is started below.
14655 */
14656 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14657 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014658
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014659 /*
14660 * Build the carrier freelist.
14661 *
14662 * Driver must have already allocated memory and set 'carrier_buf'.
14663 */
14664 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014665
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014666 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14667 asc_dvc->carr_freelist = NULL;
14668 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14669 buf_size = ADV_CARRIER_BUFSIZE;
14670 } else {
14671 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14672 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014673
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014674 do {
14675 /*
14676 * Get physical address for the carrier 'carrp'.
14677 */
14678 contig_len = sizeof(ADV_CARR_T);
14679 carr_paddr =
14680 cpu_to_le32(DvcGetPhyAddr
14681 (asc_dvc, NULL, (uchar *)carrp,
14682 (ADV_SDCNT *)&contig_len,
14683 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014684
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014685 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014686
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014687 /*
14688 * If the current carrier is not physically contiguous, then
14689 * maybe there was a page crossing. Try the next carrier aligned
14690 * start address.
14691 */
14692 if (contig_len < sizeof(ADV_CARR_T)) {
14693 carrp++;
14694 continue;
14695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014696
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014697 carrp->carr_pa = carr_paddr;
14698 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014699
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014700 /*
14701 * Insert the carrier at the beginning of the freelist.
14702 */
14703 carrp->next_vpa =
14704 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14705 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014706
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014707 carrp++;
14708 }
14709 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014710
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014711 /*
14712 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14713 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014714
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014715 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14716 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14717 return ADV_ERROR;
14718 }
14719 asc_dvc->carr_freelist = (ADV_CARR_T *)
14720 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014721
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014722 /*
14723 * The first command issued will be placed in the stopper carrier.
14724 */
14725 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014726
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014727 /*
14728 * Set RISC ICQ physical address start value.
14729 * carr_pa is LE, must be native before write
14730 */
14731 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014732
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014733 /*
14734 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14735 */
14736 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14737 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14738 return ADV_ERROR;
14739 }
14740 asc_dvc->carr_freelist = (ADV_CARR_T *)
14741 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014742
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014743 /*
14744 * The first command completed by the RISC will be placed in
14745 * the stopper.
14746 *
14747 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14748 * completed the RISC will set the ASC_RQ_STOPPER bit.
14749 */
14750 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014751
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014752 /*
14753 * Set RISC IRQ physical address start value.
14754 *
14755 * carr_pa is LE, must be native before write *
14756 */
14757 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14758 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014759
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014760 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14761 (ADV_INTR_ENABLE_HOST_INTR |
14762 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014763
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014764 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14765 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014766
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014767 /* finally, finally, gentlemen, start your engine */
14768 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014770 /*
14771 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14772 * Resets should be performed. The RISC has to be running
14773 * to issue a SCSI Bus Reset.
14774 */
14775 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14776 /*
14777 * If the BIOS Signature is present in memory, restore the
14778 * BIOS Handshake Configuration Table and do not perform
14779 * a SCSI Bus Reset.
14780 */
14781 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14782 0x55AA) {
14783 /*
14784 * Restore per TID negotiated values.
14785 */
14786 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14787 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14788 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14789 tagqng_able);
14790 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14791 AdvWriteByteLram(iop_base,
14792 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14793 max_cmd[tid]);
14794 }
14795 } else {
14796 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14797 warn_code = ASC_WARN_BUSRESET_ERROR;
14798 }
14799 }
14800 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014801
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014802 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014803}
14804
14805/*
14806 * Initialize the ASC-38C1600.
14807 *
14808 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
14809 *
14810 * For a non-fatal error return a warning code. If there are no warnings
14811 * then 0 is returned.
14812 *
14813 * Needed after initialization for error recovery.
14814 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014815static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014816{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014817 AdvPortAddr iop_base;
14818 ushort warn_code;
14819 ADV_DCNT sum;
14820 int begin_addr;
14821 int end_addr;
14822 ushort code_sum;
14823 long word;
14824 int j;
14825 int adv_asc38C1600_expanded_size;
14826 ADV_CARR_T *carrp;
14827 ADV_DCNT contig_len;
14828 ADV_SDCNT buf_size;
14829 ADV_PADDR carr_paddr;
14830 int i;
14831 ushort scsi_cfg1;
14832 uchar byte;
14833 uchar tid;
14834 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14835 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
14836 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014837
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014838 /* If there is already an error, don't continue. */
14839 if (asc_dvc->err_code != 0) {
14840 return ADV_ERROR;
14841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014842
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014843 /*
14844 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
14845 */
14846 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
14847 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14848 return ADV_ERROR;
14849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014850
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014851 warn_code = 0;
14852 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014853
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014854 /*
14855 * Save the RISC memory BIOS region before writing the microcode.
14856 * The BIOS may already be loaded and using its RISC LRAM region
14857 * so its region must be saved and restored.
14858 *
14859 * Note: This code makes the assumption, which is currently true,
14860 * that a chip reset does not clear RISC LRAM.
14861 */
14862 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14863 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14864 bios_mem[i]);
14865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014866
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014867 /*
14868 * Save current per TID negotiated values.
14869 */
14870 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14871 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14872 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
14873 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14874 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
14875 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14876 max_cmd[tid]);
14877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014878
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014879 /*
14880 * RAM BIST (Built-In Self Test)
14881 *
14882 * Address : I/O base + offset 0x38h register (byte).
14883 * Function: Bit 7-6(RW) : RAM mode
14884 * Normal Mode : 0x00
14885 * Pre-test Mode : 0x40
14886 * RAM Test Mode : 0x80
14887 * Bit 5 : unused
14888 * Bit 4(RO) : Done bit
14889 * Bit 3-0(RO) : Status
14890 * Host Error : 0x08
14891 * Int_RAM Error : 0x04
14892 * RISC Error : 0x02
14893 * SCSI Error : 0x01
14894 * No Error : 0x00
14895 *
14896 * Note: RAM BIST code should be put right here, before loading the
14897 * microcode and after saving the RISC memory BIOS region.
14898 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014899
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014900 /*
14901 * LRAM Pre-test
14902 *
14903 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14904 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14905 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14906 * to NORMAL_MODE, return an error too.
14907 */
14908 for (i = 0; i < 2; i++) {
14909 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14910 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14911 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14912 if ((byte & RAM_TEST_DONE) == 0
14913 || (byte & 0x0F) != PRE_TEST_VALUE) {
14914 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14915 return ADV_ERROR;
14916 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014917
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014918 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14919 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14920 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14921 != NORMAL_VALUE) {
14922 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14923 return ADV_ERROR;
14924 }
14925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014926
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014927 /*
14928 * LRAM Test - It takes about 1.5 ms to run through the test.
14929 *
14930 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14931 * If Done bit not set or Status not 0, save register byte, set the
14932 * err_code, and return an error.
14933 */
14934 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14935 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014936
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014937 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14938 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14939 /* Get here if Done bit not set or Status not 0. */
14940 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14941 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14942 return ADV_ERROR;
14943 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014944
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014945 /* We need to reset back to normal mode after LRAM test passes. */
14946 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014947
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014948 /*
14949 * Load the Microcode
14950 *
14951 * Write the microcode image to RISC memory starting at address 0.
14952 *
14953 */
14954 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014955
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014956 /*
14957 * Assume the following compressed format of the microcode buffer:
14958 *
14959 * 254 word (508 byte) table indexed by byte code followed
14960 * by the following byte codes:
14961 *
14962 * 1-Byte Code:
14963 * 00: Emit word 0 in table.
14964 * 01: Emit word 1 in table.
14965 * .
14966 * FD: Emit word 253 in table.
14967 *
14968 * Multi-Byte Code:
14969 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14970 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14971 */
14972 word = 0;
14973 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
14974 if (_adv_asc38C1600_buf[i] == 0xff) {
14975 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
14976 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14977 _adv_asc38C1600_buf
14978 [i +
14979 3] << 8) |
14980 _adv_asc38C1600_buf
14981 [i + 2]));
14982 word++;
14983 }
14984 i += 3;
14985 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
14986 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14987 _adv_asc38C1600_buf
14988 [i +
14989 2] << 8) |
14990 _adv_asc38C1600_buf[i
14991 +
14992 1]));
14993 i += 2;
14994 word++;
14995 } else {
14996 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14997 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
14998 word++;
14999 }
15000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015001
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015002 /*
15003 * Set 'word' for later use to clear the rest of memory and save
15004 * the expanded mcode size.
15005 */
15006 word *= 2;
15007 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015008
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015009 /*
15010 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15011 */
15012 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15013 AdvWriteWordAutoIncLram(iop_base, 0);
15014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015015
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015016 /*
15017 * Verify the microcode checksum.
15018 */
15019 sum = 0;
15020 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015021
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015022 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15023 sum += AdvReadWordAutoIncLram(iop_base);
15024 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015025
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015026 if (sum != _adv_asc38C1600_chksum) {
15027 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15028 return ADV_ERROR;
15029 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015031 /*
15032 * Restore the RISC memory BIOS region.
15033 */
15034 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15035 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15036 bios_mem[i]);
15037 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015038
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015039 /*
15040 * Calculate and write the microcode code checksum to the microcode
15041 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15042 */
15043 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15044 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15045 code_sum = 0;
15046 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15047 for (word = begin_addr; word < end_addr; word += 2) {
15048 code_sum += AdvReadWordAutoIncLram(iop_base);
15049 }
15050 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015051
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015052 /*
15053 * Read microcode version and date.
15054 */
15055 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15056 asc_dvc->cfg->mcode_date);
15057 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15058 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015059
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015060 /*
15061 * Set the chip type to indicate the ASC38C1600.
15062 */
15063 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015064
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015065 /*
15066 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15067 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15068 * cable detection and then we are able to read C_DET[3:0].
15069 *
15070 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15071 * Microcode Default Value' section below.
15072 */
15073 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15074 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15075 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015076
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015077 /*
15078 * If the PCI Configuration Command Register "Parity Error Response
15079 * Control" Bit was clear (0), then set the microcode variable
15080 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15081 * to ignore DMA parity errors.
15082 */
15083 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15084 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15085 word |= CONTROL_FLAG_IGNORE_PERR;
15086 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015089 /*
15090 * If the BIOS control flag AIPP (Asynchronous Information
15091 * Phase Protection) disable bit is not set, then set the firmware
15092 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15093 * AIPP checking and encoding.
15094 */
15095 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15096 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15097 word |= CONTROL_FLAG_ENABLE_AIPP;
15098 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015100
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015101 /*
15102 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15103 * and START_CTL_TH [3:2].
15104 */
15105 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15106 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015107
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015108 /*
15109 * Microcode operating variables for WDTR, SDTR, and command tag
Matthew Wilcox47d853c2007-07-26 11:41:33 -040015110 * queuing will be set in slave_configure() based on what a
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015111 * device reports it is capable of in Inquiry byte 7.
15112 *
15113 * If SCSI Bus Resets have been disabled, then directly set
15114 * SDTR and WDTR from the EEPROM configuration. This will allow
15115 * the BIOS and warm boot to work without a SCSI bus hang on
15116 * the Inquiry caused by host and target mismatched DTR values.
15117 * Without the SCSI Bus Reset, before an Inquiry a device can't
15118 * be assumed to be in Asynchronous, Narrow mode.
15119 */
15120 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15121 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15122 asc_dvc->wdtr_able);
15123 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15124 asc_dvc->sdtr_able);
15125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015126
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015127 /*
15128 * Set microcode operating variables for DISC and SDTR_SPEED1,
15129 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15130 * configuration values.
15131 *
15132 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15133 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15134 * without determining here whether the device supports SDTR.
15135 */
15136 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15137 asc_dvc->cfg->disc_enable);
15138 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15139 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15140 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15141 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015142
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015143 /*
15144 * Set SCSI_CFG0 Microcode Default Value.
15145 *
15146 * The microcode will set the SCSI_CFG0 register using this value
15147 * after it is started below.
15148 */
15149 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15150 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15151 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015152
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015153 /*
15154 * Calculate SCSI_CFG1 Microcode Default Value.
15155 *
15156 * The microcode will set the SCSI_CFG1 register using this value
15157 * after it is started below.
15158 *
15159 * Each ASC-38C1600 function has only two cable detect bits.
15160 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15161 */
15162 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015163
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015164 /*
15165 * If the cable is reversed all of the SCSI_CTRL register signals
15166 * will be set. Check for and return an error if this condition is
15167 * found.
15168 */
15169 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15170 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15171 return ADV_ERROR;
15172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015173
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015174 /*
15175 * Each ASC-38C1600 function has two connectors. Only an HVD device
15176 * can not be connected to either connector. An LVD device or SE device
15177 * may be connected to either connecor. If an SE device is connected,
15178 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15179 *
15180 * If an HVD device is attached, return an error.
15181 */
15182 if (scsi_cfg1 & HVD) {
15183 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15184 return ADV_ERROR;
15185 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015186
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015187 /*
15188 * Each function in the ASC-38C1600 uses only the SE cable detect and
15189 * termination because there are two connectors for each function. Each
15190 * function may use either LVD or SE mode. Corresponding the SE automatic
15191 * termination control EEPROM bits are used for each function. Each
15192 * function has its own EEPROM. If SE automatic control is enabled for
15193 * the function, then set the termination value based on a table listed
15194 * in a_condor.h.
15195 *
15196 * If manual termination is specified in the EEPROM for the function,
15197 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15198 * ready to be 'ored' into SCSI_CFG1.
15199 */
15200 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060015201 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015202 /* SE automatic termination control is enabled. */
15203 switch (scsi_cfg1 & C_DET_SE) {
15204 /* TERM_SE_HI: on, TERM_SE_LO: on */
15205 case 0x1:
15206 case 0x2:
15207 case 0x3:
15208 asc_dvc->cfg->termination |= TERM_SE;
15209 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015210
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015211 case 0x0:
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060015212 if (PCI_FUNC(pdev->devfn) == 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015213 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15214 } else {
15215 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15216 asc_dvc->cfg->termination |= TERM_SE_HI;
15217 }
15218 break;
15219 }
15220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015221
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015222 /*
15223 * Clear any set TERM_SE bits.
15224 */
15225 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015226
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015227 /*
15228 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15229 */
15230 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015231
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015232 /*
15233 * Clear Big Endian and Terminator Polarity bits and set possibly
15234 * modified termination control bits in the Microcode SCSI_CFG1
15235 * Register Value.
15236 *
15237 * Big Endian bit is not used even on big endian machines.
15238 */
15239 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015240
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015241 /*
15242 * Set SCSI_CFG1 Microcode Default Value
15243 *
15244 * Set possibly modified termination control bits in the Microcode
15245 * SCSI_CFG1 Register Value.
15246 *
15247 * The microcode will set the SCSI_CFG1 register using this value
15248 * after it is started below.
15249 */
15250 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015251
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015252 /*
15253 * Set MEM_CFG Microcode Default Value
15254 *
15255 * The microcode will set the MEM_CFG register using this value
15256 * after it is started below.
15257 *
15258 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15259 * are defined.
15260 *
15261 * ASC-38C1600 has 32KB internal memory.
15262 *
15263 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15264 * out a special 16K Adv Library and Microcode version. After the issue
15265 * resolved, we should turn back to the 32K support. Both a_condor.h and
15266 * mcode.sas files also need to be updated.
15267 *
15268 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15269 * BIOS_EN | RAM_SZ_32KB);
15270 */
15271 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15272 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015273
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015274 /*
15275 * Set SEL_MASK Microcode Default Value
15276 *
15277 * The microcode will set the SEL_MASK register using this value
15278 * after it is started below.
15279 */
15280 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15281 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015282
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015283 /*
15284 * Build the carrier freelist.
15285 *
15286 * Driver must have already allocated memory and set 'carrier_buf'.
15287 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015288
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015289 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015290
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015291 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15292 asc_dvc->carr_freelist = NULL;
15293 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15294 buf_size = ADV_CARRIER_BUFSIZE;
15295 } else {
15296 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015298
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015299 do {
15300 /*
15301 * Get physical address for the carrier 'carrp'.
15302 */
15303 contig_len = sizeof(ADV_CARR_T);
15304 carr_paddr =
15305 cpu_to_le32(DvcGetPhyAddr
15306 (asc_dvc, NULL, (uchar *)carrp,
15307 (ADV_SDCNT *)&contig_len,
15308 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015309
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015310 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015311
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015312 /*
15313 * If the current carrier is not physically contiguous, then
15314 * maybe there was a page crossing. Try the next carrier aligned
15315 * start address.
15316 */
15317 if (contig_len < sizeof(ADV_CARR_T)) {
15318 carrp++;
15319 continue;
15320 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015321
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015322 carrp->carr_pa = carr_paddr;
15323 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015324
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015325 /*
15326 * Insert the carrier at the beginning of the freelist.
15327 */
15328 carrp->next_vpa =
15329 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15330 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015331
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015332 carrp++;
15333 }
15334 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015335
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015336 /*
15337 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15338 */
15339 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15340 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15341 return ADV_ERROR;
15342 }
15343 asc_dvc->carr_freelist = (ADV_CARR_T *)
15344 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015345
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015346 /*
15347 * The first command issued will be placed in the stopper carrier.
15348 */
15349 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015350
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015351 /*
15352 * Set RISC ICQ physical address start value. Initialize the
15353 * COMMA register to the same value otherwise the RISC will
15354 * prematurely detect a command is available.
15355 */
15356 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
15357 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
15358 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015359
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015360 /*
15361 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15362 */
15363 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15364 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15365 return ADV_ERROR;
15366 }
15367 asc_dvc->carr_freelist = (ADV_CARR_T *)
15368 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015369
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015370 /*
15371 * The first command completed by the RISC will be placed in
15372 * the stopper.
15373 *
15374 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15375 * completed the RISC will set the ASC_RQ_STOPPER bit.
15376 */
15377 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015378
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015379 /*
15380 * Set RISC IRQ physical address start value.
15381 */
15382 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15383 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015384
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015385 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15386 (ADV_INTR_ENABLE_HOST_INTR |
15387 ADV_INTR_ENABLE_GLOBAL_INTR));
15388 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15389 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015390
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015391 /* finally, finally, gentlemen, start your engine */
15392 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015393
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015394 /*
15395 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15396 * Resets should be performed. The RISC has to be running
15397 * to issue a SCSI Bus Reset.
15398 */
15399 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15400 /*
15401 * If the BIOS Signature is present in memory, restore the
15402 * per TID microcode operating variables.
15403 */
15404 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15405 0x55AA) {
15406 /*
15407 * Restore per TID negotiated values.
15408 */
15409 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15410 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15411 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15412 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15413 tagqng_able);
15414 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15415 AdvWriteByteLram(iop_base,
15416 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15417 max_cmd[tid]);
15418 }
15419 } else {
15420 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15421 warn_code = ASC_WARN_BUSRESET_ERROR;
15422 }
15423 }
15424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015425
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015426 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015427}
15428
15429/*
15430 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15431 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15432 * all of this is done.
15433 *
15434 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15435 *
15436 * For a non-fatal error return a warning code. If there are no warnings
15437 * then 0 is returned.
15438 *
15439 * Note: Chip is stopped on entry.
15440 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015441static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015442{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015443 AdvPortAddr iop_base;
15444 ushort warn_code;
15445 ADVEEP_3550_CONFIG eep_config;
15446 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015447
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015448 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015449
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015450 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015451
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015452 /*
15453 * Read the board's EEPROM configuration.
15454 *
15455 * Set default values if a bad checksum is found.
15456 */
15457 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
15458 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015459
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015460 /*
15461 * Set EEPROM default values.
15462 */
15463 for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
15464 *((uchar *)&eep_config + i) =
15465 *((uchar *)&Default_3550_EEPROM_Config + i);
15466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015467
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015468 /*
15469 * Assume the 6 byte board serial number that was read
15470 * from EEPROM is correct even if the EEPROM checksum
15471 * failed.
15472 */
15473 eep_config.serial_number_word3 =
15474 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015475
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015476 eep_config.serial_number_word2 =
15477 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015478
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015479 eep_config.serial_number_word1 =
15480 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015481
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015482 AdvSet3550EEPConfig(iop_base, &eep_config);
15483 }
15484 /*
15485 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15486 * EEPROM configuration that was read.
15487 *
15488 * This is the mapping of EEPROM fields to Adv Library fields.
15489 */
15490 asc_dvc->wdtr_able = eep_config.wdtr_able;
15491 asc_dvc->sdtr_able = eep_config.sdtr_able;
15492 asc_dvc->ultra_able = eep_config.ultra_able;
15493 asc_dvc->tagqng_able = eep_config.tagqng_able;
15494 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15495 asc_dvc->max_host_qng = eep_config.max_host_qng;
15496 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15497 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15498 asc_dvc->start_motor = eep_config.start_motor;
15499 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15500 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15501 asc_dvc->no_scam = eep_config.scam_tolerant;
15502 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15503 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15504 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015505
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015506 /*
15507 * Set the host maximum queuing (max. 253, min. 16) and the per device
15508 * maximum queuing (max. 63, min. 4).
15509 */
15510 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15511 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15512 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15513 /* If the value is zero, assume it is uninitialized. */
15514 if (eep_config.max_host_qng == 0) {
15515 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15516 } else {
15517 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15518 }
15519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015520
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015521 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15522 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15523 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15524 /* If the value is zero, assume it is uninitialized. */
15525 if (eep_config.max_dvc_qng == 0) {
15526 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15527 } else {
15528 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15529 }
15530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015531
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015532 /*
15533 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15534 * set 'max_dvc_qng' to 'max_host_qng'.
15535 */
15536 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15537 eep_config.max_dvc_qng = eep_config.max_host_qng;
15538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015539
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015540 /*
15541 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15542 * values based on possibly adjusted EEPROM values.
15543 */
15544 asc_dvc->max_host_qng = eep_config.max_host_qng;
15545 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015546
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015547 /*
15548 * If the EEPROM 'termination' field is set to automatic (0), then set
15549 * the ADV_DVC_CFG 'termination' field to automatic also.
15550 *
15551 * If the termination is specified with a non-zero 'termination'
15552 * value check that a legal value is set and set the ADV_DVC_CFG
15553 * 'termination' field appropriately.
15554 */
15555 if (eep_config.termination == 0) {
15556 asc_dvc->cfg->termination = 0; /* auto termination */
15557 } else {
15558 /* Enable manual control with low off / high off. */
15559 if (eep_config.termination == 1) {
15560 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015561
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015562 /* Enable manual control with low off / high on. */
15563 } else if (eep_config.termination == 2) {
15564 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015565
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015566 /* Enable manual control with low on / high on. */
15567 } else if (eep_config.termination == 3) {
15568 asc_dvc->cfg->termination =
15569 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
15570 } else {
15571 /*
15572 * The EEPROM 'termination' field contains a bad value. Use
15573 * automatic termination instead.
15574 */
15575 asc_dvc->cfg->termination = 0;
15576 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15577 }
15578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015579
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015580 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015581}
15582
15583/*
15584 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15585 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15586 * all of this is done.
15587 *
15588 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15589 *
15590 * For a non-fatal error return a warning code. If there are no warnings
15591 * then 0 is returned.
15592 *
15593 * Note: Chip is stopped on entry.
15594 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015595static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015596{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015597 AdvPortAddr iop_base;
15598 ushort warn_code;
15599 ADVEEP_38C0800_CONFIG eep_config;
15600 int i;
15601 uchar tid, termination;
15602 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015603
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015604 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015605
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015606 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015607
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015608 /*
15609 * Read the board's EEPROM configuration.
15610 *
15611 * Set default values if a bad checksum is found.
15612 */
15613 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
15614 eep_config.check_sum) {
15615 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015616
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015617 /*
15618 * Set EEPROM default values.
15619 */
15620 for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
15621 *((uchar *)&eep_config + i) =
15622 *((uchar *)&Default_38C0800_EEPROM_Config + i);
15623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015624
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015625 /*
15626 * Assume the 6 byte board serial number that was read
15627 * from EEPROM is correct even if the EEPROM checksum
15628 * failed.
15629 */
15630 eep_config.serial_number_word3 =
15631 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015632
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015633 eep_config.serial_number_word2 =
15634 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015635
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015636 eep_config.serial_number_word1 =
15637 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015638
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015639 AdvSet38C0800EEPConfig(iop_base, &eep_config);
15640 }
15641 /*
15642 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
15643 * EEPROM configuration that was read.
15644 *
15645 * This is the mapping of EEPROM fields to Adv Library fields.
15646 */
15647 asc_dvc->wdtr_able = eep_config.wdtr_able;
15648 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15649 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15650 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15651 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15652 asc_dvc->tagqng_able = eep_config.tagqng_able;
15653 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15654 asc_dvc->max_host_qng = eep_config.max_host_qng;
15655 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15656 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15657 asc_dvc->start_motor = eep_config.start_motor;
15658 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15659 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15660 asc_dvc->no_scam = eep_config.scam_tolerant;
15661 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15662 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15663 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015664
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015665 /*
15666 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15667 * are set, then set an 'sdtr_able' bit for it.
15668 */
15669 asc_dvc->sdtr_able = 0;
15670 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15671 if (tid == 0) {
15672 sdtr_speed = asc_dvc->sdtr_speed1;
15673 } else if (tid == 4) {
15674 sdtr_speed = asc_dvc->sdtr_speed2;
15675 } else if (tid == 8) {
15676 sdtr_speed = asc_dvc->sdtr_speed3;
15677 } else if (tid == 12) {
15678 sdtr_speed = asc_dvc->sdtr_speed4;
15679 }
15680 if (sdtr_speed & ADV_MAX_TID) {
15681 asc_dvc->sdtr_able |= (1 << tid);
15682 }
15683 sdtr_speed >>= 4;
15684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015685
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015686 /*
15687 * Set the host maximum queuing (max. 253, min. 16) and the per device
15688 * maximum queuing (max. 63, min. 4).
15689 */
15690 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15691 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15692 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15693 /* If the value is zero, assume it is uninitialized. */
15694 if (eep_config.max_host_qng == 0) {
15695 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15696 } else {
15697 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15698 }
15699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015700
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015701 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15702 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15703 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15704 /* If the value is zero, assume it is uninitialized. */
15705 if (eep_config.max_dvc_qng == 0) {
15706 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15707 } else {
15708 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15709 }
15710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015711
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015712 /*
15713 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15714 * set 'max_dvc_qng' to 'max_host_qng'.
15715 */
15716 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15717 eep_config.max_dvc_qng = eep_config.max_host_qng;
15718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015720 /*
15721 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15722 * values based on possibly adjusted EEPROM values.
15723 */
15724 asc_dvc->max_host_qng = eep_config.max_host_qng;
15725 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015726
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015727 /*
15728 * If the EEPROM 'termination' field is set to automatic (0), then set
15729 * the ADV_DVC_CFG 'termination' field to automatic also.
15730 *
15731 * If the termination is specified with a non-zero 'termination'
15732 * value check that a legal value is set and set the ADV_DVC_CFG
15733 * 'termination' field appropriately.
15734 */
15735 if (eep_config.termination_se == 0) {
15736 termination = 0; /* auto termination for SE */
15737 } else {
15738 /* Enable manual control with low off / high off. */
15739 if (eep_config.termination_se == 1) {
15740 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015741
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015742 /* Enable manual control with low off / high on. */
15743 } else if (eep_config.termination_se == 2) {
15744 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015746 /* Enable manual control with low on / high on. */
15747 } else if (eep_config.termination_se == 3) {
15748 termination = TERM_SE;
15749 } else {
15750 /*
15751 * The EEPROM 'termination_se' field contains a bad value.
15752 * Use automatic termination instead.
15753 */
15754 termination = 0;
15755 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15756 }
15757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015758
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015759 if (eep_config.termination_lvd == 0) {
15760 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
15761 } else {
15762 /* Enable manual control with low off / high off. */
15763 if (eep_config.termination_lvd == 1) {
15764 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015765
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015766 /* Enable manual control with low off / high on. */
15767 } else if (eep_config.termination_lvd == 2) {
15768 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015770 /* Enable manual control with low on / high on. */
15771 } else if (eep_config.termination_lvd == 3) {
15772 asc_dvc->cfg->termination = termination | TERM_LVD;
15773 } else {
15774 /*
15775 * The EEPROM 'termination_lvd' field contains a bad value.
15776 * Use automatic termination instead.
15777 */
15778 asc_dvc->cfg->termination = termination;
15779 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15780 }
15781 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015782
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015783 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015784}
15785
15786/*
15787 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
15788 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
15789 * all of this is done.
15790 *
15791 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15792 *
15793 * For a non-fatal error return a warning code. If there are no warnings
15794 * then 0 is returned.
15795 *
15796 * Note: Chip is stopped on entry.
15797 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015798static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015799{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015800 AdvPortAddr iop_base;
15801 ushort warn_code;
15802 ADVEEP_38C1600_CONFIG eep_config;
15803 int i;
15804 uchar tid, termination;
15805 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015806
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015807 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015808
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015809 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015810
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015811 /*
15812 * Read the board's EEPROM configuration.
15813 *
15814 * Set default values if a bad checksum is found.
15815 */
15816 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
15817 eep_config.check_sum) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060015818 struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015819 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015820
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015821 /*
15822 * Set EEPROM default values.
15823 */
15824 for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
Matthew Wilcox13ac2d92007-07-30 08:10:23 -060015825 if (i == 1 && PCI_FUNC(pdev->devfn) != 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015826 /*
15827 * Set Function 1 EEPROM Word 0 MSB
15828 *
15829 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
15830 * EEPROM bits.
15831 *
15832 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
15833 * old Mac system booting problem. The Expansion ROM must
15834 * be disabled in Function 1 for these systems.
15835 *
15836 */
15837 *((uchar *)&eep_config + i) =
15838 ((*
15839 ((uchar *)&Default_38C1600_EEPROM_Config
15840 +
15841 i)) &
15842 (~
15843 (((ADV_EEPROM_BIOS_ENABLE |
15844 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015845
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015846 /*
15847 * Set the INTAB (bit 11) if the GPIO 0 input indicates
15848 * the Function 1 interrupt line is wired to INTA.
15849 *
15850 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
15851 * 1 - Function 1 interrupt line wired to INT A.
15852 * 0 - Function 1 interrupt line wired to INT B.
15853 *
15854 * Note: Adapter boards always have Function 0 wired to INTA.
15855 * Put all 5 GPIO bits in input mode and then read
15856 * their input values.
15857 */
15858 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
15859 0);
15860 if (AdvReadByteRegister
15861 (iop_base, IOPB_GPIO_DATA) & 0x01) {
15862 /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
15863 *((uchar *)&eep_config + i) |=
15864 ((ADV_EEPROM_INTAB >> 8) & 0xFF);
15865 }
15866 } else {
15867 *((uchar *)&eep_config + i) =
15868 *((uchar *)&Default_38C1600_EEPROM_Config
15869 + i);
15870 }
15871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015872
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015873 /*
15874 * Assume the 6 byte board serial number that was read
15875 * from EEPROM is correct even if the EEPROM checksum
15876 * failed.
15877 */
15878 eep_config.serial_number_word3 =
15879 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015880
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015881 eep_config.serial_number_word2 =
15882 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015883
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015884 eep_config.serial_number_word1 =
15885 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015886
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015887 AdvSet38C1600EEPConfig(iop_base, &eep_config);
15888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015889
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015890 /*
15891 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15892 * EEPROM configuration that was read.
15893 *
15894 * This is the mapping of EEPROM fields to Adv Library fields.
15895 */
15896 asc_dvc->wdtr_able = eep_config.wdtr_able;
15897 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15898 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15899 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15900 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15901 asc_dvc->ppr_able = 0;
15902 asc_dvc->tagqng_able = eep_config.tagqng_able;
15903 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15904 asc_dvc->max_host_qng = eep_config.max_host_qng;
15905 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15906 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
15907 asc_dvc->start_motor = eep_config.start_motor;
15908 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15909 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15910 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015911
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015912 /*
15913 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15914 * are set, then set an 'sdtr_able' bit for it.
15915 */
15916 asc_dvc->sdtr_able = 0;
15917 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15918 if (tid == 0) {
15919 sdtr_speed = asc_dvc->sdtr_speed1;
15920 } else if (tid == 4) {
15921 sdtr_speed = asc_dvc->sdtr_speed2;
15922 } else if (tid == 8) {
15923 sdtr_speed = asc_dvc->sdtr_speed3;
15924 } else if (tid == 12) {
15925 sdtr_speed = asc_dvc->sdtr_speed4;
15926 }
15927 if (sdtr_speed & ASC_MAX_TID) {
15928 asc_dvc->sdtr_able |= (1 << tid);
15929 }
15930 sdtr_speed >>= 4;
15931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015932
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015933 /*
15934 * Set the host maximum queuing (max. 253, min. 16) and the per device
15935 * maximum queuing (max. 63, min. 4).
15936 */
15937 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15938 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15939 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15940 /* If the value is zero, assume it is uninitialized. */
15941 if (eep_config.max_host_qng == 0) {
15942 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15943 } else {
15944 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15945 }
15946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015947
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015948 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15949 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15950 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15951 /* If the value is zero, assume it is uninitialized. */
15952 if (eep_config.max_dvc_qng == 0) {
15953 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15954 } else {
15955 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15956 }
15957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015958
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015959 /*
15960 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15961 * set 'max_dvc_qng' to 'max_host_qng'.
15962 */
15963 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15964 eep_config.max_dvc_qng = eep_config.max_host_qng;
15965 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015966
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015967 /*
15968 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
15969 * values based on possibly adjusted EEPROM values.
15970 */
15971 asc_dvc->max_host_qng = eep_config.max_host_qng;
15972 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015973
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015974 /*
15975 * If the EEPROM 'termination' field is set to automatic (0), then set
15976 * the ASC_DVC_CFG 'termination' field to automatic also.
15977 *
15978 * If the termination is specified with a non-zero 'termination'
15979 * value check that a legal value is set and set the ASC_DVC_CFG
15980 * 'termination' field appropriately.
15981 */
15982 if (eep_config.termination_se == 0) {
15983 termination = 0; /* auto termination for SE */
15984 } else {
15985 /* Enable manual control with low off / high off. */
15986 if (eep_config.termination_se == 1) {
15987 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015988
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015989 /* Enable manual control with low off / high on. */
15990 } else if (eep_config.termination_se == 2) {
15991 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015992
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015993 /* Enable manual control with low on / high on. */
15994 } else if (eep_config.termination_se == 3) {
15995 termination = TERM_SE;
15996 } else {
15997 /*
15998 * The EEPROM 'termination_se' field contains a bad value.
15999 * Use automatic termination instead.
16000 */
16001 termination = 0;
16002 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16003 }
16004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016005
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016006 if (eep_config.termination_lvd == 0) {
16007 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16008 } else {
16009 /* Enable manual control with low off / high off. */
16010 if (eep_config.termination_lvd == 1) {
16011 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016012
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016013 /* Enable manual control with low off / high on. */
16014 } else if (eep_config.termination_lvd == 2) {
16015 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016016
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016017 /* Enable manual control with low on / high on. */
16018 } else if (eep_config.termination_lvd == 3) {
16019 asc_dvc->cfg->termination = termination | TERM_LVD;
16020 } else {
16021 /*
16022 * The EEPROM 'termination_lvd' field contains a bad value.
16023 * Use automatic termination instead.
16024 */
16025 asc_dvc->cfg->termination = termination;
16026 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16027 }
16028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016029
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016030 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016031}
16032
16033/*
16034 * Read EEPROM configuration into the specified buffer.
16035 *
16036 * Return a checksum based on the EEPROM configuration read.
16037 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016038static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016039AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16040{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016041 ushort wval, chksum;
16042 ushort *wbuf;
16043 int eep_addr;
16044 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016045
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016046 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16047 wbuf = (ushort *)cfg_buf;
16048 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016049
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016050 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16051 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16052 wval = AdvReadEEPWord(iop_base, eep_addr);
16053 chksum += wval; /* Checksum is calculated from word values. */
16054 if (*charfields++) {
16055 *wbuf = le16_to_cpu(wval);
16056 } else {
16057 *wbuf = wval;
16058 }
16059 }
16060 /* Read checksum word. */
16061 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16062 wbuf++;
16063 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016064
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016065 /* Read rest of EEPROM not covered by the checksum. */
16066 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16067 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16068 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16069 if (*charfields++) {
16070 *wbuf = le16_to_cpu(*wbuf);
16071 }
16072 }
16073 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016074}
16075
16076/*
16077 * Read EEPROM configuration into the specified buffer.
16078 *
16079 * Return a checksum based on the EEPROM configuration read.
16080 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016081static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016082AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016083{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016084 ushort wval, chksum;
16085 ushort *wbuf;
16086 int eep_addr;
16087 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016089 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16090 wbuf = (ushort *)cfg_buf;
16091 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016092
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016093 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16094 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16095 wval = AdvReadEEPWord(iop_base, eep_addr);
16096 chksum += wval; /* Checksum is calculated from word values. */
16097 if (*charfields++) {
16098 *wbuf = le16_to_cpu(wval);
16099 } else {
16100 *wbuf = wval;
16101 }
16102 }
16103 /* Read checksum word. */
16104 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16105 wbuf++;
16106 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016107
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016108 /* Read rest of EEPROM not covered by the checksum. */
16109 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16110 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16111 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16112 if (*charfields++) {
16113 *wbuf = le16_to_cpu(*wbuf);
16114 }
16115 }
16116 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016117}
16118
16119/*
16120 * Read EEPROM configuration into the specified buffer.
16121 *
16122 * Return a checksum based on the EEPROM configuration read.
16123 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016124static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016125AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016126{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016127 ushort wval, chksum;
16128 ushort *wbuf;
16129 int eep_addr;
16130 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016131
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016132 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16133 wbuf = (ushort *)cfg_buf;
16134 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016135
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016136 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16137 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16138 wval = AdvReadEEPWord(iop_base, eep_addr);
16139 chksum += wval; /* Checksum is calculated from word values. */
16140 if (*charfields++) {
16141 *wbuf = le16_to_cpu(wval);
16142 } else {
16143 *wbuf = wval;
16144 }
16145 }
16146 /* Read checksum word. */
16147 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16148 wbuf++;
16149 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016150
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016151 /* Read rest of EEPROM not covered by the checksum. */
16152 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16153 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16154 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16155 if (*charfields++) {
16156 *wbuf = le16_to_cpu(*wbuf);
16157 }
16158 }
16159 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016160}
16161
16162/*
16163 * Read the EEPROM from specified location
16164 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016165static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016166{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016167 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16168 ASC_EEP_CMD_READ | eep_word_addr);
16169 AdvWaitEEPCmd(iop_base);
16170 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016171}
16172
16173/*
16174 * Wait for EEPROM command to complete
16175 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016176static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016177{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016178 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016179
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016180 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16181 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16182 ASC_EEP_CMD_DONE) {
16183 break;
16184 }
16185 DvcSleepMilliSecond(1);
16186 }
16187 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16188 0) {
16189 ASC_ASSERT(0);
16190 }
16191 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016192}
16193
16194/*
16195 * Write the EEPROM from 'cfg_buf'.
16196 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016197void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016198AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16199{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016200 ushort *wbuf;
16201 ushort addr, chksum;
16202 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016203
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016204 wbuf = (ushort *)cfg_buf;
16205 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16206 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016207
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016208 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16209 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016210
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016211 /*
16212 * Write EEPROM from word 0 to word 20.
16213 */
16214 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16215 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16216 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016217
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016218 if (*charfields++) {
16219 word = cpu_to_le16(*wbuf);
16220 } else {
16221 word = *wbuf;
16222 }
16223 chksum += *wbuf; /* Checksum is calculated from word values. */
16224 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16225 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16226 ASC_EEP_CMD_WRITE | addr);
16227 AdvWaitEEPCmd(iop_base);
16228 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016230
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016231 /*
16232 * Write EEPROM checksum at word 21.
16233 */
16234 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16235 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16236 AdvWaitEEPCmd(iop_base);
16237 wbuf++;
16238 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016239
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016240 /*
16241 * Write EEPROM OEM name at words 22 to 29.
16242 */
16243 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16244 addr < ADV_EEP_MAX_WORD_ADDR; 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 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16253 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16254 ASC_EEP_CMD_WRITE | addr);
16255 AdvWaitEEPCmd(iop_base);
16256 }
16257 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16258 AdvWaitEEPCmd(iop_base);
16259 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016260}
16261
16262/*
16263 * Write the EEPROM from 'cfg_buf'.
16264 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016265void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016266AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016267{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016268 ushort *wbuf;
16269 ushort *charfields;
16270 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016271
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016272 wbuf = (ushort *)cfg_buf;
16273 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16274 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016275
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016276 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16277 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016278
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016279 /*
16280 * Write EEPROM from word 0 to word 20.
16281 */
16282 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16283 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16284 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016285
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016286 if (*charfields++) {
16287 word = cpu_to_le16(*wbuf);
16288 } else {
16289 word = *wbuf;
16290 }
16291 chksum += *wbuf; /* Checksum is calculated from word values. */
16292 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16293 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16294 ASC_EEP_CMD_WRITE | addr);
16295 AdvWaitEEPCmd(iop_base);
16296 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16297 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016298
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016299 /*
16300 * Write EEPROM checksum at word 21.
16301 */
16302 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16303 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16304 AdvWaitEEPCmd(iop_base);
16305 wbuf++;
16306 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016307
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016308 /*
16309 * Write EEPROM OEM name at words 22 to 29.
16310 */
16311 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16312 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16313 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016314
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016315 if (*charfields++) {
16316 word = cpu_to_le16(*wbuf);
16317 } else {
16318 word = *wbuf;
16319 }
16320 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16321 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16322 ASC_EEP_CMD_WRITE | addr);
16323 AdvWaitEEPCmd(iop_base);
16324 }
16325 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16326 AdvWaitEEPCmd(iop_base);
16327 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016328}
16329
16330/*
16331 * Write the EEPROM from 'cfg_buf'.
16332 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016333void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016334AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016335{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016336 ushort *wbuf;
16337 ushort *charfields;
16338 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016339
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016340 wbuf = (ushort *)cfg_buf;
16341 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16342 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016343
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016344 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16345 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016346
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016347 /*
16348 * Write EEPROM from word 0 to word 20.
16349 */
16350 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16351 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16352 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016353
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016354 if (*charfields++) {
16355 word = cpu_to_le16(*wbuf);
16356 } else {
16357 word = *wbuf;
16358 }
16359 chksum += *wbuf; /* Checksum is calculated from word values. */
16360 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16361 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16362 ASC_EEP_CMD_WRITE | addr);
16363 AdvWaitEEPCmd(iop_base);
16364 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016366
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016367 /*
16368 * Write EEPROM checksum at word 21.
16369 */
16370 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16371 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16372 AdvWaitEEPCmd(iop_base);
16373 wbuf++;
16374 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016375
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016376 /*
16377 * Write EEPROM OEM name at words 22 to 29.
16378 */
16379 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16380 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16381 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016383 if (*charfields++) {
16384 word = cpu_to_le16(*wbuf);
16385 } else {
16386 word = *wbuf;
16387 }
16388 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16389 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16390 ASC_EEP_CMD_WRITE | addr);
16391 AdvWaitEEPCmd(iop_base);
16392 }
16393 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16394 AdvWaitEEPCmd(iop_base);
16395 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016396}
16397
16398/* a_advlib.c */
16399/*
16400 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
16401 *
16402 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
16403 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
16404 * RISC to notify it a new command is ready to be executed.
16405 *
16406 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
16407 * set to SCSI_MAX_RETRY.
16408 *
16409 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
16410 * for DMA addresses or math operations are byte swapped to little-endian
16411 * order.
16412 *
16413 * Return:
16414 * ADV_SUCCESS(1) - The request was successfully queued.
16415 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
16416 * request completes.
16417 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
16418 * host IC error.
16419 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016420static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016421{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016422 ulong last_int_level;
16423 AdvPortAddr iop_base;
16424 ADV_DCNT req_size;
16425 ADV_PADDR req_paddr;
16426 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016427
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016428 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016429
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016430 /*
16431 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
16432 */
16433 if (scsiq->target_id > ADV_MAX_TID) {
16434 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
16435 scsiq->done_status = QD_WITH_ERROR;
16436 return ADV_ERROR;
16437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016438
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016439 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016441 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016442
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016443 /*
16444 * Allocate a carrier ensuring at least one carrier always
16445 * remains on the freelist and initialize fields.
16446 */
16447 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
16448 DvcLeaveCritical(last_int_level);
16449 return ADV_BUSY;
16450 }
16451 asc_dvc->carr_freelist = (ADV_CARR_T *)
16452 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
16453 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016454
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016455 /*
16456 * Set the carrier to be a stopper by setting 'next_vpa'
16457 * to the stopper value. The current stopper will be changed
16458 * below to point to the new stopper.
16459 */
16460 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016461
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016462 /*
16463 * Clear the ADV_SCSI_REQ_Q done flag.
16464 */
16465 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016466
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016467 req_size = sizeof(ADV_SCSI_REQ_Q);
16468 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
16469 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016470
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016471 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
16472 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016473
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016474 /* Wait for assertion before making little-endian */
16475 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016476
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016477 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
16478 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
16479 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016480
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016481 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
16482 /*
16483 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
16484 * order during initialization.
16485 */
16486 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016487
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016488 /*
16489 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
16490 * the microcode. The newly allocated stopper will become the new
16491 * stopper.
16492 */
16493 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016494
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016495 /*
16496 * Set the 'next_vpa' pointer for the old stopper to be the
16497 * physical address of the new stopper. The RISC can only
16498 * follow physical addresses.
16499 */
16500 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016501
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016502 /*
16503 * Set the host adapter stopper pointer to point to the new carrier.
16504 */
16505 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016506
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016507 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16508 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16509 /*
16510 * Tickle the RISC to tell it to read its Command Queue Head pointer.
16511 */
16512 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
16513 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16514 /*
16515 * Clear the tickle value. In the ASC-3550 the RISC flag
16516 * command 'clr_tickle_a' does not work unless the host
16517 * value is cleared.
16518 */
16519 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16520 ADV_TICKLE_NOP);
16521 }
16522 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16523 /*
16524 * Notify the RISC a carrier is ready by writing the physical
16525 * address of the new carrier stopper to the COMMA register.
16526 */
16527 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
16528 le32_to_cpu(new_carrp->carr_pa));
16529 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016530
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016531 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016532
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016533 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016534}
16535
16536/*
16537 * Reset SCSI Bus and purge all outstanding requests.
16538 *
16539 * Return Value:
16540 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
16541 * ADV_FALSE(0) - Microcode command failed.
16542 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
16543 * may be hung which requires driver recovery.
16544 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016545static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016546{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016547 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016548
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016549 /*
16550 * Send the SCSI Bus Reset idle start idle command which asserts
16551 * the SCSI Bus Reset signal.
16552 */
16553 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
16554 if (status != ADV_TRUE) {
16555 return status;
16556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016557
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016558 /*
16559 * Delay for the specified SCSI Bus Reset hold time.
16560 *
16561 * The hold time delay is done on the host because the RISC has no
16562 * microsecond accurate timer.
16563 */
16564 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016565
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016566 /*
16567 * Send the SCSI Bus Reset end idle command which de-asserts
16568 * the SCSI Bus Reset signal and purges any pending requests.
16569 */
16570 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
16571 if (status != ADV_TRUE) {
16572 return status;
16573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016575 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016577 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016578}
16579
16580/*
16581 * Reset chip and SCSI Bus.
16582 *
16583 * Return Value:
16584 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
16585 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
16586 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016587static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016588{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016589 int status;
16590 ushort wdtr_able, sdtr_able, tagqng_able;
16591 ushort ppr_able = 0;
16592 uchar tid, max_cmd[ADV_MAX_TID + 1];
16593 AdvPortAddr iop_base;
16594 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016595
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016596 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016597
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016598 /*
16599 * Save current per TID negotiated values.
16600 */
16601 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16602 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16603 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16604 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16605 }
16606 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16607 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16608 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16609 max_cmd[tid]);
16610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016611
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016612 /*
16613 * Force the AdvInitAsc3550/38C0800Driver() function to
16614 * perform a SCSI Bus Reset by clearing the BIOS signature word.
16615 * The initialization functions assumes a SCSI Bus Reset is not
16616 * needed if the BIOS signature word is present.
16617 */
16618 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
16619 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016620
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016621 /*
16622 * Stop chip and reset it.
16623 */
16624 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
16625 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
16626 DvcSleepMilliSecond(100);
16627 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
16628 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016630 /*
16631 * Reset Adv Library error code, if any, and try
16632 * re-initializing the chip.
16633 */
16634 asc_dvc->err_code = 0;
16635 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16636 status = AdvInitAsc38C1600Driver(asc_dvc);
16637 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16638 status = AdvInitAsc38C0800Driver(asc_dvc);
16639 } else {
16640 status = AdvInitAsc3550Driver(asc_dvc);
16641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016643 /* Translate initialization return value to status value. */
16644 if (status == 0) {
16645 status = ADV_TRUE;
16646 } else {
16647 status = ADV_FALSE;
16648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016649
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016650 /*
16651 * Restore the BIOS signature word.
16652 */
16653 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016654
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016655 /*
16656 * Restore per TID negotiated values.
16657 */
16658 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16659 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16660 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16661 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16662 }
16663 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16664 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16665 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16666 max_cmd[tid]);
16667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016668
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016669 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016670}
16671
16672/*
16673 * Adv Library Interrupt Service Routine
16674 *
16675 * This function is called by a driver's interrupt service routine.
16676 * The function disables and re-enables interrupts.
16677 *
16678 * When a microcode idle command is completed, the ADV_DVC_VAR
16679 * 'idle_cmd_done' field is set to ADV_TRUE.
16680 *
16681 * Note: AdvISR() can be called when interrupts are disabled or even
16682 * when there is no hardware interrupt condition present. It will
16683 * always check for completed idle commands and microcode requests.
16684 * This is an important feature that shouldn't be changed because it
16685 * allows commands to be completed from polling mode loops.
16686 *
16687 * Return:
16688 * ADV_TRUE(1) - interrupt was pending
16689 * ADV_FALSE(0) - no interrupt was pending
16690 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016691static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016692{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016693 AdvPortAddr iop_base;
16694 uchar int_stat;
16695 ushort target_bit;
16696 ADV_CARR_T *free_carrp;
16697 ADV_VADDR irq_next_vpa;
16698 int flags;
16699 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016700
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016701 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016702
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016703 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016704
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016705 /* Reading the register clears the interrupt. */
16706 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016707
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016708 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
16709 ADV_INTR_STATUS_INTRC)) == 0) {
16710 DvcLeaveCritical(flags);
16711 return ADV_FALSE;
16712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016713
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016714 /*
16715 * Notify the driver of an asynchronous microcode condition by
Matthew Wilcox895d6b42007-07-26 11:57:06 -040016716 * calling the adv_async_callback function. The function
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016717 * is passed the microcode ASC_MC_INTRB_CODE byte value.
16718 */
16719 if (int_stat & ADV_INTR_STATUS_INTRB) {
16720 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016721
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016722 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016723
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016724 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16725 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16726 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
16727 asc_dvc->carr_pending_cnt != 0) {
16728 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16729 ADV_TICKLE_A);
16730 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16731 AdvWriteByteRegister(iop_base,
16732 IOPB_TICKLE,
16733 ADV_TICKLE_NOP);
16734 }
16735 }
16736 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016737
Matthew Wilcox895d6b42007-07-26 11:57:06 -040016738 adv_async_callback(asc_dvc, intrb_code);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016740
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016741 /*
16742 * Check if the IRQ stopper carrier contains a completed request.
16743 */
16744 while (((irq_next_vpa =
16745 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
16746 /*
16747 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
16748 * The RISC will have set 'areq_vpa' to a virtual address.
16749 *
16750 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
16751 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
16752 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
16753 * in AdvExeScsiQueue().
16754 */
16755 scsiq = (ADV_SCSI_REQ_Q *)
16756 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016757
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016758 /*
16759 * Request finished with good status and the queue was not
16760 * DMAed to host memory by the firmware. Set all status fields
16761 * to indicate good status.
16762 */
16763 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
16764 scsiq->done_status = QD_NO_ERROR;
16765 scsiq->host_status = scsiq->scsi_status = 0;
16766 scsiq->data_cnt = 0L;
16767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016768
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016769 /*
16770 * Advance the stopper pointer to the next carrier
16771 * ignoring the lower four bits. Free the previous
16772 * stopper carrier.
16773 */
16774 free_carrp = asc_dvc->irq_sp;
16775 asc_dvc->irq_sp = (ADV_CARR_T *)
16776 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016777
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016778 free_carrp->next_vpa =
16779 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
16780 asc_dvc->carr_freelist = free_carrp;
16781 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016782
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016783 ASC_ASSERT(scsiq != NULL);
16784 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016785
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016786 /*
16787 * Clear request microcode control flag.
16788 */
16789 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016790
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016791 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016792 * Notify the driver of the completed request by passing
16793 * the ADV_SCSI_REQ_Q pointer to its callback function.
16794 */
16795 scsiq->a_flag |= ADV_SCSIQ_DONE;
Matthew Wilcox895d6b42007-07-26 11:57:06 -040016796 adv_isr_callback(asc_dvc, scsiq);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016797 /*
16798 * Note: After the driver callback function is called, 'scsiq'
16799 * can no longer be referenced.
16800 *
16801 * Fall through and continue processing other completed
16802 * requests...
16803 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016804
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016805 /*
16806 * Disable interrupts again in case the driver inadvertently
16807 * enabled interrupts in its callback function.
16808 *
16809 * The DvcEnterCritical() return value is ignored, because
16810 * the 'flags' saved when AdvISR() was first entered will be
16811 * used to restore the interrupt flag on exit.
16812 */
16813 (void)DvcEnterCritical();
16814 }
16815 DvcLeaveCritical(flags);
16816 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016817}
16818
16819/*
16820 * Send an idle command to the chip and wait for completion.
16821 *
16822 * Command completion is polled for once per microsecond.
16823 *
16824 * The function can be called from anywhere including an interrupt handler.
16825 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
16826 * functions to prevent reentrancy.
16827 *
16828 * Return Values:
16829 * ADV_TRUE - command completed successfully
16830 * ADV_FALSE - command failed
16831 * ADV_ERROR - command timed out
16832 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016833static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070016834AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016835 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016836{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016837 ulong last_int_level;
16838 int result;
16839 ADV_DCNT i, j;
16840 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016841
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016842 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016843
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016844 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016845
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016846 /*
16847 * Clear the idle command status which is set by the microcode
16848 * to a non-zero value to indicate when the command is completed.
16849 * The non-zero result is one of the IDLE_CMD_STATUS_* values
16850 * defined in a_advlib.h.
16851 */
16852 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016853
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016854 /*
16855 * Write the idle command value after the idle command parameter
16856 * has been written to avoid a race condition. If the order is not
16857 * followed, the microcode may process the idle command before the
16858 * parameters have been written to LRAM.
16859 */
16860 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
16861 cpu_to_le32(idle_cmd_parameter));
16862 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016863
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016864 /*
16865 * Tickle the RISC to tell it to process the idle command.
16866 */
16867 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
16868 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16869 /*
16870 * Clear the tickle value. In the ASC-3550 the RISC flag
16871 * command 'clr_tickle_b' does not work unless the host
16872 * value is cleared.
16873 */
16874 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
16875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016876
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016877 /* Wait for up to 100 millisecond for the idle command to timeout. */
16878 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
16879 /* Poll once each microsecond for command completion. */
16880 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
16881 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
16882 result);
16883 if (result != 0) {
16884 DvcLeaveCritical(last_int_level);
16885 return result;
16886 }
16887 DvcDelayMicroSecond(asc_dvc, (ushort)1);
16888 }
16889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016890
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016891 ASC_ASSERT(0); /* The idle command should never timeout. */
16892 DvcLeaveCritical(last_int_level);
16893 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016894}
16895
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060016896static int __devinit
16897advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
16898{
16899 int req_cnt = 0;
16900 adv_req_t *reqp = NULL;
16901 int sg_cnt = 0;
16902 adv_sgblk_t *sgp;
16903 int warn_code, err_code;
16904
16905 /*
16906 * Allocate buffer carrier structures. The total size
16907 * is about 4 KB, so allocate all at once.
16908 */
16909 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
16910 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
16911
16912 if (!boardp->carrp)
16913 goto kmalloc_failed;
16914
16915 /*
16916 * Allocate up to 'max_host_qng' request structures for the Wide
16917 * board. The total size is about 16 KB, so allocate all at once.
16918 * If the allocation fails decrement and try again.
16919 */
16920 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
16921 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
16922
16923 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
16924 "bytes %lu\n", reqp, req_cnt,
16925 (ulong)sizeof(adv_req_t) * req_cnt);
16926
16927 if (reqp)
16928 break;
16929 }
16930
16931 if (!reqp)
16932 goto kmalloc_failed;
16933
16934 boardp->orig_reqp = reqp;
16935
16936 /*
16937 * Allocate up to ADV_TOT_SG_BLOCK request structures for
16938 * the Wide board. Each structure is about 136 bytes.
16939 */
16940 boardp->adv_sgblkp = NULL;
16941 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
16942 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
16943
16944 if (!sgp)
16945 break;
16946
16947 sgp->next_sgblkp = boardp->adv_sgblkp;
16948 boardp->adv_sgblkp = sgp;
16949
16950 }
16951
16952 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
16953 sg_cnt, sizeof(adv_sgblk_t),
16954 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
16955
16956 if (!boardp->adv_sgblkp)
16957 goto kmalloc_failed;
16958
16959 adv_dvc_varp->carrier_buf = boardp->carrp;
16960
16961 /*
16962 * Point 'adv_reqp' to the request structures and
16963 * link them together.
16964 */
16965 req_cnt--;
16966 reqp[req_cnt].next_reqp = NULL;
16967 for (; req_cnt > 0; req_cnt--) {
16968 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
16969 }
16970 boardp->adv_reqp = &reqp[0];
16971
16972 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
16973 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
16974 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
16975 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
16976 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
16977 "\n");
16978 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
16979 } else {
16980 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
16981 "\n");
16982 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
16983 }
16984 err_code = adv_dvc_varp->err_code;
16985
16986 if (warn_code || err_code) {
16987 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
16988 " error 0x%x\n", boardp->id, warn_code, err_code);
16989 }
16990
16991 goto exit;
16992
16993 kmalloc_failed:
16994 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
16995 "failed\n", boardp->id);
16996 err_code = ADV_ERROR;
16997 exit:
16998 return err_code;
16999}
17000
17001static void advansys_wide_free_mem(asc_board_t *boardp)
17002{
17003 kfree(boardp->carrp);
17004 boardp->carrp = NULL;
17005 kfree(boardp->orig_reqp);
17006 boardp->orig_reqp = boardp->adv_reqp = NULL;
17007 while (boardp->adv_sgblkp) {
17008 adv_sgblk_t *sgp = boardp->adv_sgblkp;
17009 boardp->adv_sgblkp = sgp->next_sgblkp;
17010 kfree(sgp);
17011 }
17012}
17013
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017014static struct Scsi_Host *__devinit
17015advansys_board_found(int iop, struct device *dev, int bus_type)
17016{
17017 struct Scsi_Host *shost;
17018 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
17019 asc_board_t *boardp;
17020 ASC_DVC_VAR *asc_dvc_varp = NULL;
17021 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017022 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017023 int warn_code, err_code;
17024 int ret;
17025
17026 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017027 * Register the adapter, get its configuration, and
17028 * initialize it.
17029 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017030 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
17031 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017032 if (!shost)
17033 return NULL;
17034
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017035 /* Initialize private per board data */
17036 boardp = ASC_BOARDP(shost);
17037 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017038 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017039 spin_lock_init(&boardp->lock);
Matthew Wilcox394dbf32007-07-26 11:56:40 -040017040 boardp->dev = dev;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017041
17042 /*
17043 * Handle both narrow and wide boards.
17044 *
17045 * If a Wide board was detected, set the board structure
17046 * wide board flag. Set-up the board structure based on
17047 * the board type.
17048 */
17049#ifdef CONFIG_PCI
17050 if (bus_type == ASC_IS_PCI &&
17051 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17052 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17053 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17054 boardp->flags |= ASC_IS_WIDE_BOARD;
17055 }
17056#endif /* CONFIG_PCI */
17057
17058 if (ASC_NARROW_BOARD(boardp)) {
17059 ASC_DBG(1, "advansys_board_found: narrow board\n");
17060 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17061 asc_dvc_varp->bus_type = bus_type;
17062 asc_dvc_varp->drv_ptr = boardp;
17063 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17064 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17065 asc_dvc_varp->iop_base = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017066 } else {
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017067#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017068 ASC_DBG(1, "advansys_board_found: wide board\n");
17069 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17070 adv_dvc_varp->drv_ptr = boardp;
17071 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017072 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17073 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17074 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17075 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17076 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17077 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17078 } else {
17079 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17080 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17081 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017082
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017083 boardp->asc_n_io_port = pci_resource_len(pdev, 1);
17084 boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1),
17085 boardp->asc_n_io_port);
17086 if (!boardp->ioremap_addr) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017087 ASC_PRINT3
17088 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017089 boardp->id, pci_resource_start(pdev, 1),
17090 boardp->asc_n_io_port);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017091 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017092 }
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017093 adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr
Matthew Wilcox71f36112007-07-30 08:04:53 -060017094 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017095 adv_dvc_varp->iop_base);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017096
17097 /*
17098 * Even though it isn't used to access wide boards, other
17099 * than for the debug line below, save I/O Port address so
17100 * that it can be reported.
17101 */
17102 boardp->ioport = iop;
17103
Matthew Wilcox57ba5fe2007-07-26 11:55:07 -040017104 ASC_DBG2(1, "advansys_board_found: iopb_chip_id_1 0x%x, "
17105 "iopw_chip_id_0 0x%x\n", (ushort)inp(iop + 1),
17106 (ushort)inpw(iop));
17107#endif /* CONFIG_PCI */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017108 }
17109
17110#ifdef CONFIG_PROC_FS
17111 /*
17112 * Allocate buffer for printing information from
17113 * /proc/scsi/advansys/[0...].
17114 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017115 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
17116 if (!boardp->prtbuf) {
17117 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
17118 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
17119 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017120 }
17121#endif /* CONFIG_PROC_FS */
17122
17123 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017124 /*
17125 * Set the board bus type and PCI IRQ before
17126 * calling AscInitGetConfig().
17127 */
17128 switch (asc_dvc_varp->bus_type) {
17129#ifdef CONFIG_ISA
17130 case ASC_IS_ISA:
17131 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017132 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017133 break;
17134 case ASC_IS_VL:
17135 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017136 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017137 break;
17138 case ASC_IS_EISA:
17139 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017140 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017141 break;
17142#endif /* CONFIG_ISA */
17143#ifdef CONFIG_PCI
17144 case ASC_IS_PCI:
17145 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017146 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017147 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017148 break;
17149#endif /* CONFIG_PCI */
17150 default:
17151 ASC_PRINT2
17152 ("advansys_board_found: board %d: unknown adapter type: %d\n",
17153 boardp->id, asc_dvc_varp->bus_type);
17154 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017155 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017156 break;
17157 }
17158 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017159 /*
17160 * For Wide boards set PCI information before calling
17161 * AdvInitGetConfig().
17162 */
17163#ifdef CONFIG_PCI
17164 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017165 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017166 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017167#endif /* CONFIG_PCI */
17168 }
17169
17170 /*
17171 * Read the board configuration.
17172 */
17173 if (ASC_NARROW_BOARD(boardp)) {
17174 /*
17175 * NOTE: AscInitGetConfig() may change the board's
17176 * bus_type value. The bus_type value should no
17177 * longer be used. If the bus_type field must be
17178 * referenced only use the bit-wise AND operator "&".
17179 */
17180 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
17181 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
17182 case 0: /* No error */
17183 break;
17184 case ASC_WARN_IO_PORT_ROTATE:
17185 ASC_PRINT1
17186 ("AscInitGetConfig: board %d: I/O port address modified\n",
17187 boardp->id);
17188 break;
17189 case ASC_WARN_AUTO_CONFIG:
17190 ASC_PRINT1
17191 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
17192 boardp->id);
17193 break;
17194 case ASC_WARN_EEPROM_CHKSUM:
17195 ASC_PRINT1
17196 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
17197 boardp->id);
17198 break;
17199 case ASC_WARN_IRQ_MODIFIED:
17200 ASC_PRINT1
17201 ("AscInitGetConfig: board %d: IRQ modified\n",
17202 boardp->id);
17203 break;
17204 case ASC_WARN_CMD_QNG_CONFLICT:
17205 ASC_PRINT1
17206 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
17207 boardp->id);
17208 break;
17209 default:
17210 ASC_PRINT2
17211 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
17212 boardp->id, ret);
17213 break;
17214 }
17215 if ((err_code = asc_dvc_varp->err_code) != 0) {
17216 ASC_PRINT3
17217 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17218 boardp->id,
17219 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
17220 }
17221 } else {
17222 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
Matthew Wilcox394dbf32007-07-26 11:56:40 -040017223
17224 ret = AdvInitGetConfig(pdev, adv_dvc_varp);
17225 if (ret != 0) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017226 ASC_PRINT2
17227 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
17228 boardp->id, ret);
17229 }
17230 if ((err_code = adv_dvc_varp->err_code) != 0) {
17231 ASC_PRINT2
17232 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
17233 boardp->id, adv_dvc_varp->err_code);
17234 }
17235 }
17236
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017237 if (err_code != 0)
17238 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017239
17240 /*
17241 * Save the EEPROM configuration so that it can be displayed
17242 * from /proc/scsi/advansys/[0...].
17243 */
17244 if (ASC_NARROW_BOARD(boardp)) {
17245
17246 ASCEEP_CONFIG *ep;
17247
17248 /*
17249 * Set the adapter's target id bit in the 'init_tidmask' field.
17250 */
17251 boardp->init_tidmask |=
17252 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
17253
17254 /*
17255 * Save EEPROM settings for the board.
17256 */
17257 ep = &boardp->eep_config.asc_eep;
17258
17259 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
17260 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
17261 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
17262 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
17263 ep->start_motor = asc_dvc_varp->start_motor;
17264 ep->cntl = asc_dvc_varp->dvc_cntl;
17265 ep->no_scam = asc_dvc_varp->no_scam;
17266 ep->max_total_qng = asc_dvc_varp->max_total_qng;
17267 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
17268 /* 'max_tag_qng' is set to the same value for every device. */
17269 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
17270 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
17271 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
17272 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
17273 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
17274 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
17275 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
17276
17277 /*
17278 * Modify board configuration.
17279 */
17280 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
Matthew Wilcox394dbf32007-07-26 11:56:40 -040017281 switch (ret = AscInitSetConfig(pdev, asc_dvc_varp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017282 case 0: /* No error. */
17283 break;
17284 case ASC_WARN_IO_PORT_ROTATE:
17285 ASC_PRINT1
17286 ("AscInitSetConfig: board %d: I/O port address modified\n",
17287 boardp->id);
17288 break;
17289 case ASC_WARN_AUTO_CONFIG:
17290 ASC_PRINT1
17291 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
17292 boardp->id);
17293 break;
17294 case ASC_WARN_EEPROM_CHKSUM:
17295 ASC_PRINT1
17296 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
17297 boardp->id);
17298 break;
17299 case ASC_WARN_IRQ_MODIFIED:
17300 ASC_PRINT1
17301 ("AscInitSetConfig: board %d: IRQ modified\n",
17302 boardp->id);
17303 break;
17304 case ASC_WARN_CMD_QNG_CONFLICT:
17305 ASC_PRINT1
17306 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
17307 boardp->id);
17308 break;
17309 default:
17310 ASC_PRINT2
17311 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
17312 boardp->id, ret);
17313 break;
17314 }
17315 if (asc_dvc_varp->err_code != 0) {
17316 ASC_PRINT3
17317 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17318 boardp->id,
17319 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017320 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017321 }
17322
17323 /*
17324 * Finish initializing the 'Scsi_Host' structure.
17325 */
17326 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
17327 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
17328 shost->irq = asc_dvc_varp->irq_no;
17329 }
17330 } else {
17331 ADVEEP_3550_CONFIG *ep_3550;
17332 ADVEEP_38C0800_CONFIG *ep_38C0800;
17333 ADVEEP_38C1600_CONFIG *ep_38C1600;
17334
17335 /*
17336 * Save Wide EEP Configuration Information.
17337 */
17338 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17339 ep_3550 = &boardp->eep_config.adv_3550_eep;
17340
17341 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
17342 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
17343 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17344 ep_3550->termination = adv_dvc_varp->cfg->termination;
17345 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
17346 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
17347 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
17348 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
17349 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
17350 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
17351 ep_3550->start_motor = adv_dvc_varp->start_motor;
17352 ep_3550->scsi_reset_delay =
17353 adv_dvc_varp->scsi_reset_wait;
17354 ep_3550->serial_number_word1 =
17355 adv_dvc_varp->cfg->serial1;
17356 ep_3550->serial_number_word2 =
17357 adv_dvc_varp->cfg->serial2;
17358 ep_3550->serial_number_word3 =
17359 adv_dvc_varp->cfg->serial3;
17360 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17361 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
17362
17363 ep_38C0800->adapter_scsi_id =
17364 adv_dvc_varp->chip_scsi_id;
17365 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
17366 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17367 ep_38C0800->termination_lvd =
17368 adv_dvc_varp->cfg->termination;
17369 ep_38C0800->disc_enable =
17370 adv_dvc_varp->cfg->disc_enable;
17371 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
17372 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
17373 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17374 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17375 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17376 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17377 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17378 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17379 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
17380 ep_38C0800->scsi_reset_delay =
17381 adv_dvc_varp->scsi_reset_wait;
17382 ep_38C0800->serial_number_word1 =
17383 adv_dvc_varp->cfg->serial1;
17384 ep_38C0800->serial_number_word2 =
17385 adv_dvc_varp->cfg->serial2;
17386 ep_38C0800->serial_number_word3 =
17387 adv_dvc_varp->cfg->serial3;
17388 } else {
17389 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
17390
17391 ep_38C1600->adapter_scsi_id =
17392 adv_dvc_varp->chip_scsi_id;
17393 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
17394 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17395 ep_38C1600->termination_lvd =
17396 adv_dvc_varp->cfg->termination;
17397 ep_38C1600->disc_enable =
17398 adv_dvc_varp->cfg->disc_enable;
17399 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
17400 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
17401 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17402 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17403 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17404 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17405 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17406 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17407 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
17408 ep_38C1600->scsi_reset_delay =
17409 adv_dvc_varp->scsi_reset_wait;
17410 ep_38C1600->serial_number_word1 =
17411 adv_dvc_varp->cfg->serial1;
17412 ep_38C1600->serial_number_word2 =
17413 adv_dvc_varp->cfg->serial2;
17414 ep_38C1600->serial_number_word3 =
17415 adv_dvc_varp->cfg->serial3;
17416 }
17417
17418 /*
17419 * Set the adapter's target id bit in the 'init_tidmask' field.
17420 */
17421 boardp->init_tidmask |=
17422 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017423 }
17424
17425 /*
17426 * Channels are numbered beginning with 0. For AdvanSys one host
17427 * structure supports one channel. Multi-channel boards have a
17428 * separate host structure for each channel.
17429 */
17430 shost->max_channel = 0;
17431 if (ASC_NARROW_BOARD(boardp)) {
17432 shost->max_id = ASC_MAX_TID + 1;
17433 shost->max_lun = ASC_MAX_LUN + 1;
17434
17435 shost->io_port = asc_dvc_varp->iop_base;
17436 boardp->asc_n_io_port = ASC_IOADR_GAP;
17437 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
17438
17439 /* Set maximum number of queues the adapter can handle. */
17440 shost->can_queue = asc_dvc_varp->max_total_qng;
17441 } else {
17442 shost->max_id = ADV_MAX_TID + 1;
17443 shost->max_lun = ADV_MAX_LUN + 1;
17444
17445 /*
17446 * Save the I/O Port address and length even though
17447 * I/O ports are not used to access Wide boards.
17448 * Instead the Wide boards are accessed with
17449 * PCI Memory Mapped I/O.
17450 */
17451 shost->io_port = iop;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017452
17453 shost->this_id = adv_dvc_varp->chip_scsi_id;
17454
17455 /* Set maximum number of queues the adapter can handle. */
17456 shost->can_queue = adv_dvc_varp->max_host_qng;
17457 }
17458
17459 /*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017460 * Following v1.3.89, 'cmd_per_lun' is no longer needed
17461 * and should be set to zero.
17462 *
17463 * But because of a bug introduced in v1.3.89 if the driver is
17464 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
17465 * SCSI function 'allocate_device' will panic. To allow the driver
17466 * to work as a module in these kernels set 'cmd_per_lun' to 1.
17467 *
17468 * Note: This is wrong. cmd_per_lun should be set to the depth
17469 * you want on untagged devices always.
17470 #ifdef MODULE
17471 */
17472 shost->cmd_per_lun = 1;
17473/* #else
17474 shost->cmd_per_lun = 0;
17475#endif */
17476
17477 /*
17478 * Set the maximum number of scatter-gather elements the
17479 * adapter can handle.
17480 */
17481 if (ASC_NARROW_BOARD(boardp)) {
17482 /*
17483 * Allow two commands with 'sg_tablesize' scatter-gather
17484 * elements to be executed simultaneously. This value is
17485 * the theoretical hardware limit. It may be decreased
17486 * below.
17487 */
17488 shost->sg_tablesize =
17489 (((asc_dvc_varp->max_total_qng - 2) / 2) *
17490 ASC_SG_LIST_PER_Q) + 1;
17491 } else {
17492 shost->sg_tablesize = ADV_MAX_SG_LIST;
17493 }
17494
17495 /*
17496 * The value of 'sg_tablesize' can not exceed the SCSI
17497 * mid-level driver definition of SG_ALL. SG_ALL also
17498 * must not be exceeded, because it is used to define the
17499 * size of the scatter-gather table in 'struct asc_sg_head'.
17500 */
17501 if (shost->sg_tablesize > SG_ALL) {
17502 shost->sg_tablesize = SG_ALL;
17503 }
17504
17505 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
17506
17507 /* BIOS start address. */
17508 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017509 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
17510 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017511 } else {
17512 /*
17513 * Fill-in BIOS board variables. The Wide BIOS saves
17514 * information in LRAM that is used by the driver.
17515 */
17516 AdvReadWordLram(adv_dvc_varp->iop_base,
17517 BIOS_SIGNATURE, boardp->bios_signature);
17518 AdvReadWordLram(adv_dvc_varp->iop_base,
17519 BIOS_VERSION, boardp->bios_version);
17520 AdvReadWordLram(adv_dvc_varp->iop_base,
17521 BIOS_CODESEG, boardp->bios_codeseg);
17522 AdvReadWordLram(adv_dvc_varp->iop_base,
17523 BIOS_CODELEN, boardp->bios_codelen);
17524
17525 ASC_DBG2(1,
17526 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
17527 boardp->bios_signature, boardp->bios_version);
17528
17529 ASC_DBG2(1,
17530 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
17531 boardp->bios_codeseg, boardp->bios_codelen);
17532
17533 /*
17534 * If the BIOS saved a valid signature, then fill in
17535 * the BIOS code segment base address.
17536 */
17537 if (boardp->bios_signature == 0x55AA) {
17538 /*
17539 * Convert x86 realmode code segment to a linear
17540 * address by shifting left 4.
17541 */
17542 shost->base = ((ulong)boardp->bios_codeseg << 4);
17543 } else {
17544 shost->base = 0;
17545 }
17546 }
17547
17548 /*
17549 * Register Board Resources - I/O Port, DMA, IRQ
17550 */
17551
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017552 /* Register DMA Channel for Narrow boards. */
17553 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
17554#ifdef CONFIG_ISA
17555 if (ASC_NARROW_BOARD(boardp)) {
17556 /* Register DMA channel for ISA bus. */
17557 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
17558 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017559 ret = request_dma(shost->dma_channel, "advansys");
17560 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017561 ASC_PRINT3
17562 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
17563 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017564 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017565 }
17566 AscEnableIsaDma(shost->dma_channel);
17567 }
17568 }
17569#endif /* CONFIG_ISA */
17570
17571 /* Register IRQ Number. */
17572 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017573
17574 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
17575 "advansys", shost);
17576
17577 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017578 if (ret == -EBUSY) {
17579 ASC_PRINT2
17580 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
17581 boardp->id, shost->irq);
17582 } else if (ret == -EINVAL) {
17583 ASC_PRINT2
17584 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
17585 boardp->id, shost->irq);
17586 } else {
17587 ASC_PRINT3
17588 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
17589 boardp->id, shost->irq, ret);
17590 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017591 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017592 }
17593
17594 /*
17595 * Initialize board RISC chip and enable interrupts.
17596 */
17597 if (ASC_NARROW_BOARD(boardp)) {
17598 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
17599 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
17600 err_code = asc_dvc_varp->err_code;
17601
17602 if (warn_code || err_code) {
17603 ASC_PRINT4
17604 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
17605 boardp->id,
17606 asc_dvc_varp->init_state, warn_code, err_code);
17607 }
17608 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017609 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017610 }
17611
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017612 if (err_code != 0)
17613 goto err_free_wide_mem;
17614
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017615 ASC_DBG_PRT_SCSI_HOST(2, shost);
17616
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017617 ret = scsi_add_host(shost, dev);
17618 if (ret)
17619 goto err_free_wide_mem;
17620
17621 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017622 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017623
17624 err_free_wide_mem:
17625 advansys_wide_free_mem(boardp);
17626 free_irq(shost->irq, shost);
17627 err_free_dma:
17628 if (shost->dma_channel != NO_ISA_DMA)
17629 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017630 err_free_proc:
17631 kfree(boardp->prtbuf);
17632 err_unmap:
17633 if (boardp->ioremap_addr)
17634 iounmap(boardp->ioremap_addr);
17635 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017636 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017637 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017638}
17639
17640/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017641 * advansys_release()
17642 *
17643 * Release resources allocated for a single AdvanSys adapter.
17644 */
17645static int advansys_release(struct Scsi_Host *shost)
17646{
17647 asc_board_t *boardp;
17648
17649 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017650 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017651 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017652 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017653 if (shost->dma_channel != NO_ISA_DMA) {
17654 ASC_DBG(1, "advansys_release: free_dma()\n");
17655 free_dma(shost->dma_channel);
17656 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017657 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017658 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017659 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017660 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017661 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017662 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017663 ASC_DBG(1, "advansys_release: end\n");
17664 return 0;
17665}
17666
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017667static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
17668 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
17669 0x0210, 0x0230, 0x0250, 0x0330
17670};
17671
17672static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
17673{
17674 PortAddr iop_base = _asc_def_iop_base[id];
17675 struct Scsi_Host *shost;
17676
17677 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017678 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
17679 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017680 return -ENODEV;
17681 }
17682 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017683 if (!AscFindSignature(iop_base))
17684 goto nodev;
17685 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
17686 goto nodev;
17687
17688 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017689 if (!shost)
17690 goto nodev;
17691
17692 dev_set_drvdata(dev, shost);
17693 return 0;
17694
17695 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060017696 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017697 return -ENODEV;
17698}
17699
17700static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
17701{
Matthew Wilcox71f36112007-07-30 08:04:53 -060017702 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017703 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060017704 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017705 return 0;
17706}
17707
17708static struct isa_driver advansys_isa_driver = {
17709 .probe = advansys_isa_probe,
17710 .remove = __devexit_p(advansys_isa_remove),
17711 .driver = {
17712 .owner = THIS_MODULE,
17713 .name = "advansys",
17714 },
17715};
17716
17717static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
17718{
17719 PortAddr iop_base = _asc_def_iop_base[id];
17720 struct Scsi_Host *shost;
17721
17722 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017723 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
17724 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017725 return -ENODEV;
17726 }
17727 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017728 if (!AscFindSignature(iop_base))
17729 goto nodev;
17730 /*
17731 * I don't think this condition can actually happen, but the old
17732 * driver did it, and the chances of finding a VLB setup in 2007
17733 * to do testing with is slight to none.
17734 */
17735 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
17736 goto nodev;
17737
17738 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017739 if (!shost)
17740 goto nodev;
17741
17742 dev_set_drvdata(dev, shost);
17743 return 0;
17744
17745 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060017746 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017747 return -ENODEV;
17748}
17749
17750static struct isa_driver advansys_vlb_driver = {
17751 .probe = advansys_vlb_probe,
17752 .remove = __devexit_p(advansys_isa_remove),
17753 .driver = {
17754 .owner = THIS_MODULE,
17755 .name = "advansys",
17756 },
17757};
17758
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017759static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
17760 { "ABP7401" },
17761 { "ABP7501" },
17762 { "" }
17763};
17764
17765MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
17766
17767/*
17768 * EISA is a little more tricky than PCI; each EISA device may have two
17769 * channels, and this driver is written to make each channel its own Scsi_Host
17770 */
17771struct eisa_scsi_data {
17772 struct Scsi_Host *host[2];
17773};
17774
17775static int __devinit advansys_eisa_probe(struct device *dev)
17776{
17777 int i, ioport;
17778 int err;
17779 struct eisa_device *edev = to_eisa_device(dev);
17780 struct eisa_scsi_data *data;
17781
17782 err = -ENOMEM;
17783 data = kzalloc(sizeof(*data), GFP_KERNEL);
17784 if (!data)
17785 goto fail;
17786 ioport = edev->base_addr + 0xc30;
17787
17788 err = -ENODEV;
17789 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017790 if (!request_region(ioport, ASC_IOADR_GAP, "advansys")) {
17791 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
17792 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017793 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017794 }
17795 if (!AscFindSignature(ioport)) {
17796 release_region(ioport, ASC_IOADR_GAP);
17797 continue;
17798 }
17799
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017800 /*
17801 * I don't know why we need to do this for EISA chips, but
17802 * not for any others. It looks to be equivalent to
17803 * AscGetChipCfgMsw, but I may have overlooked something,
17804 * so I'm not converting it until I get an EISA board to
17805 * test with.
17806 */
17807 inw(ioport + 4);
17808 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017809 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017810 err = 0;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017811 } else {
17812 release_region(ioport, ASC_IOADR_GAP);
17813 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017814 }
17815
17816 if (err) {
17817 kfree(data);
17818 } else {
17819 dev_set_drvdata(dev, data);
17820 }
17821
17822 fail:
17823 return err;
17824}
17825
17826static __devexit int advansys_eisa_remove(struct device *dev)
17827{
17828 int i;
17829 struct eisa_scsi_data *data = dev_get_drvdata(dev);
17830
17831 for (i = 0; i < 2; i++) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060017832 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017833 struct Scsi_Host *shost = data->host[i];
17834 if (!shost)
17835 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017836 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017837 advansys_release(shost);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017838 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017839 }
17840
17841 kfree(data);
17842 return 0;
17843}
17844
17845static struct eisa_driver advansys_eisa_driver = {
17846 .id_table = advansys_eisa_table,
17847 .driver = {
17848 .name = "advansys",
17849 .probe = advansys_eisa_probe,
17850 .remove = __devexit_p(advansys_eisa_remove),
17851 }
17852};
17853
Dave Jones2672ea82006-08-02 17:11:49 -040017854/* PCI Devices supported by this driver */
17855static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017856 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
17857 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17858 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
17859 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17860 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
17861 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17862 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
17863 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17864 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
17865 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17866 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
17867 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
17868 {}
Dave Jones2672ea82006-08-02 17:11:49 -040017869};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017870
Dave Jones2672ea82006-08-02 17:11:49 -040017871MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017872
Matthew Wilcox9649af32007-07-26 21:51:47 -060017873static void __devinit advansys_set_latency(struct pci_dev *pdev)
17874{
17875 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
17876 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
17877 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
17878 } else {
17879 u8 latency;
17880 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
17881 if (latency < 0x20)
17882 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
17883 }
17884}
17885
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017886static int __devinit
17887advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
17888{
17889 int err, ioport;
17890 struct Scsi_Host *shost;
17891
17892 err = pci_enable_device(pdev);
17893 if (err)
17894 goto fail;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017895 err = pci_request_regions(pdev, "advansys");
17896 if (err)
17897 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060017898 pci_set_master(pdev);
17899 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017900
17901 if (pci_resource_len(pdev, 0) == 0)
17902 goto nodev;
17903
17904 ioport = pci_resource_start(pdev, 0);
17905 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
17906
17907 if (!shost)
17908 goto nodev;
17909
17910 pci_set_drvdata(pdev, shost);
17911 return 0;
17912
17913 nodev:
17914 err = -ENODEV;
Matthew Wilcox71f36112007-07-30 08:04:53 -060017915 pci_release_regions(pdev);
17916 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017917 pci_disable_device(pdev);
17918 fail:
17919 return err;
17920}
17921
17922static void __devexit advansys_pci_remove(struct pci_dev *pdev)
17923{
17924 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060017925 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017926 pci_disable_device(pdev);
17927}
17928
17929static struct pci_driver advansys_pci_driver = {
17930 .name = "advansys",
17931 .id_table = advansys_pci_tbl,
17932 .probe = advansys_pci_probe,
17933 .remove = __devexit_p(advansys_pci_remove),
17934};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040017935
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017936static int __init advansys_init(void)
17937{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017938 int error;
17939
17940 error = isa_register_driver(&advansys_isa_driver,
17941 ASC_IOADR_TABLE_MAX_IX);
17942 if (error)
17943 goto fail;
17944
17945 error = isa_register_driver(&advansys_vlb_driver,
17946 ASC_IOADR_TABLE_MAX_IX);
17947 if (error)
17948 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017949
17950 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017951 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017952 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017953
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017954 error = pci_register_driver(&advansys_pci_driver);
17955 if (error)
17956 goto unregister_eisa;
17957
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017958 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017959
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017960 unregister_eisa:
17961 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017962 unregister_vlb:
17963 isa_unregister_driver(&advansys_vlb_driver);
17964 unregister_isa:
17965 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017966 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017967 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017968}
17969
17970static void __exit advansys_exit(void)
17971{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017972 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060017973 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060017974 isa_unregister_driver(&advansys_vlb_driver);
17975 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017976}
17977
17978module_init(advansys_init);
17979module_exit(advansys_exit);
17980
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040017981MODULE_LICENSE("GPL");