blob: 277002a546016473fbe90eb3cd3f3e0227f4cf63 [file] [log] [blame]
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04001#define ASC_VERSION "3.4" /* AdvanSys Driver Version */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002
3/*
4 * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
5 *
6 * Copyright (c) 1995-2000 Advanced System Products, Inc.
7 * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -04008 * Copyright (c) 2007 Matthew Wilcox <matthew@wil.cx>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * All Rights Reserved.
10 *
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
19 * changed its name to ConnectCom Solutions, Inc.
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040020 * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 */
22
23/*
24
25 Documentation for the AdvanSys Driver
26
27 A. Linux Kernels Supported by this Driver
28 B. Adapters Supported by this Driver
29 C. Linux source files modified by AdvanSys Driver
30 D. Source Comments
31 E. Driver Compile Time Options and Debugging
32 F. Driver LILO Option
33 G. Tests to run before releasing new driver
34 H. Release History
35 I. Known Problems/Fix List
36 J. Credits (Chronological Order)
37
38 A. Linux Kernels Supported by this Driver
39
40 This driver has been tested in the following Linux kernels: v2.2.18
41 v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86,
42 alpha, and PowerPC platforms.
43
44 B. Adapters Supported by this Driver
45
46 AdvanSys (Advanced System Products, Inc.) manufactures the following
47 RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
48 (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
49 buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
50 transfer) SCSI Host Adapters for the PCI bus.
51
52 The CDB counts below indicate the number of SCSI CDB (Command
53 Descriptor Block) requests that can be stored in the RISC chip
54 cache and board LRAM. A CDB is a single SCSI command. The driver
55 detect routine will display the number of CDBs available for each
56 adapter detected. The number of CDBs used by the driver can be
57 lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
58
59 Laptop Products:
60 ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater)
61
62 Connectivity Products:
63 ABP510/5150 - Bus-Master ISA (240 CDB)
64 ABP5140 - Bus-Master ISA PnP (16 CDB)
65 ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
66 ABP902/3902 - Bus-Master PCI (16 CDB)
67 ABP3905 - Bus-Master PCI (16 CDB)
68 ABP915 - Bus-Master PCI (16 CDB)
69 ABP920 - Bus-Master PCI (16 CDB)
70 ABP3922 - Bus-Master PCI (16 CDB)
71 ABP3925 - Bus-Master PCI (16 CDB)
72 ABP930 - Bus-Master PCI (16 CDB)
73 ABP930U - Bus-Master PCI Ultra (16 CDB)
74 ABP930UA - Bus-Master PCI Ultra (16 CDB)
75 ABP960 - Bus-Master PCI MAC/PC (16 CDB)
76 ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
77
78 Single Channel Products:
79 ABP542 - Bus-Master ISA with floppy (240 CDB)
80 ABP742 - Bus-Master EISA (240 CDB)
81 ABP842 - Bus-Master VL (240 CDB)
82 ABP940 - Bus-Master PCI (240 CDB)
83 ABP940U - Bus-Master PCI Ultra (240 CDB)
84 ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
85 ABP970 - Bus-Master PCI MAC/PC (240 CDB)
86 ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
87 ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
88 ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
89 ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
90 ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
91
92 Multi-Channel Products:
93 ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
94 ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
95 ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
96 ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
97 ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
98 ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
99 ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
100 ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
101 ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB)
102
103 C. Linux source files modified by AdvanSys Driver
104
105 This section for historical purposes documents the changes
106 originally made to the Linux kernel source to add the advansys
107 driver. As Linux has changed some of these files have also
108 been modified.
109
110 1. linux/arch/i386/config.in:
111
112 bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y
113
114 2. linux/drivers/scsi/hosts.c:
115
116 #ifdef CONFIG_SCSI_ADVANSYS
117 #include "advansys.h"
118 #endif
119
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100120 and after "static struct scsi_host_template builtin_scsi_hosts[] =":
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
122 #ifdef CONFIG_SCSI_ADVANSYS
123 ADVANSYS,
124 #endif
125
126 3. linux/drivers/scsi/Makefile:
127
128 ifdef CONFIG_SCSI_ADVANSYS
129 SCSI_SRCS := $(SCSI_SRCS) advansys.c
130 SCSI_OBJS := $(SCSI_OBJS) advansys.o
131 else
132 SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o
133 endif
134
135 4. linux/init/main.c:
136
137 extern void advansys_setup(char *str, int *ints);
138
139 and add the following lines to the bootsetups[] array.
140
141 #ifdef CONFIG_SCSI_ADVANSYS
142 { "advansys=", advansys_setup },
143 #endif
144
145 D. Source Comments
146
147 1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
148
149 2. This driver should be maintained in multiple files. But to make
150 it easier to include with Linux and to follow Linux conventions,
151 the whole driver is maintained in the source files advansys.h and
152 advansys.c. In this file logical sections of the driver begin with
153 a comment that contains '---'. The following are the logical sections
154 of the driver below.
155
156 --- Linux Version
157 --- Linux Include File
158 --- Driver Options
159 --- Debugging Header
160 --- Asc Library Constants and Macros
161 --- Adv Library Constants and Macros
162 --- Driver Constants and Macros
163 --- Driver Structures
164 --- Driver Data
165 --- Driver Function Prototypes
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100166 --- Linux 'struct scsi_host_template' and advansys_setup() Functions
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 --- Loadable Driver Support
168 --- Miscellaneous Driver Functions
169 --- Functions Required by the Asc Library
170 --- Functions Required by the Adv Library
171 --- Tracing and Debugging Functions
172 --- Asc Library Functions
173 --- Adv Library Functions
174
175 3. The string 'XXX' is used to flag code that needs to be re-written
176 or that contains a problem that needs to be addressed.
177
178 4. I have stripped comments from and reformatted the source for the
179 Asc Library and Adv Library to reduce the size of this file. This
180 source can be found under the following headings. The Asc Library
181 is used to support Narrow Boards. The Adv Library is used to
182 support Wide Boards.
183
184 --- Asc Library Constants and Macros
185 --- Adv Library Constants and Macros
186 --- Asc Library Functions
187 --- Adv Library Functions
188
189 E. Driver Compile Time Options and Debugging
190
191 In this source file the following constants can be defined. They are
192 defined in the source below. Both of these options are enabled by
193 default.
194
195 1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
196
197 Enabling this option adds assertion logic statements to the
198 driver. If an assertion fails a message will be displayed to
199 the console, but the system will continue to operate. Any
200 assertions encountered should be reported to the person
201 responsible for the driver. Assertion statements may proactively
202 detect problems with the driver and facilitate fixing these
203 problems. Enabling assertions will add a small overhead to the
204 execution of the driver.
205
206 2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled)
207
208 Enabling this option adds tracing functions to the driver and
209 the ability to set a driver tracing level at boot time. This
210 option will also export symbols not required outside the driver to
211 the kernel name space. This option is very useful for debugging
212 the driver, but it will add to the size of the driver execution
213 image and add overhead to the execution of the driver.
214
215 The amount of debugging output can be controlled with the global
216 variable 'asc_dbglvl'. The higher the number the more output. By
217 default the debug level is 0.
218
219 If the driver is loaded at boot time and the LILO Driver Option
220 is included in the system, the debug level can be changed by
221 specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
222 first three hex digits of the pseudo I/O Port must be set to
223 'deb' and the fourth hex digit specifies the debug level: 0 - F.
224 The following command line will look for an adapter at 0x330
225 and set the debug level to 2.
226
227 linux advansys=0x330,0,0,0,0xdeb2
228
229 If the driver is built as a loadable module this variable can be
230 defined when the driver is loaded. The following insmod command
231 will set the debug level to one.
232
233 insmod advansys.o asc_dbglvl=1
234
235 Debugging Message Levels:
236 0: Errors Only
237 1: High-Level Tracing
238 2-N: Verbose Tracing
239
240 To enable debug output to console, please make sure that:
241
242 a. System and kernel logging is enabled (syslogd, klogd running).
243 b. Kernel messages are routed to console output. Check
244 /etc/syslog.conf for an entry similar to this:
245
246 kern.* /dev/console
247
248 c. klogd is started with the appropriate -c parameter
249 (e.g. klogd -c 8)
250
251 This will cause printk() messages to be be displayed on the
252 current console. Refer to the klogd(8) and syslogd(8) man pages
253 for details.
254
255 Alternatively you can enable printk() to console with this
256 program. However, this is not the 'official' way to do this.
257 Debug output is logged in /var/log/messages.
258
259 main()
260 {
261 syscall(103, 7, 0, 0);
262 }
263
264 Increasing LOG_BUF_LEN in kernel/printk.c to something like
265 40960 allows more debug messages to be buffered in the kernel
266 and written to the console or log file.
267
268 3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0)
269
270 Enabling this option adds statistics collection and display
271 through /proc to the driver. The information is useful for
272 monitoring driver and device performance. It will add to the
273 size of the driver execution image and add minor overhead to
274 the execution of the driver.
275
276 Statistics are maintained on a per adapter basis. Driver entry
277 point call counts and transfer size counts are maintained.
278 Statistics are only available for kernels greater than or equal
279 to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
280
281 AdvanSys SCSI adapter files have the following path name format:
282
Matthew Wilcoxc304ec92007-07-30 09:18:45 -0600283 /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
285 This information can be displayed with cat. For example:
286
287 cat /proc/scsi/advansys/0
288
289 When ADVANSYS_STATS is not defined the AdvanSys /proc files only
290 contain adapter and device configuration information.
291
292 F. Driver LILO Option
293
294 If init/main.c is modified as described in the 'Directions for Adding
295 the AdvanSys Driver to Linux' section (B.4.) above, the driver will
296 recognize the 'advansys' LILO command line and /etc/lilo.conf option.
297 This option can be used to either disable I/O port scanning or to limit
298 scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and
299 PCI boards will still be searched for and detected. This option only
300 affects searching for ISA and VL boards.
301
302 Examples:
303 1. Eliminate I/O port scanning:
304 boot: linux advansys=
305 or
306 boot: linux advansys=0x0
307 2. Limit I/O port scanning to one I/O port:
308 boot: linux advansys=0x110
309 3. Limit I/O port scanning to four I/O ports:
310 boot: linux advansys=0x110,0x210,0x230,0x330
311
312 For a loadable module the same effect can be achieved by setting
313 the 'asc_iopflag' variable and 'asc_ioport' array when loading
314 the driver, e.g.
315
316 insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
317
318 If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
319 I/O Port may be added to specify the driver debug level. Refer to
320 the 'Driver Compile Time Options and Debugging' section above for
321 more information.
322
323 G. Tests to run before releasing new driver
324
325 1. In the supported kernels verify there are no warning or compile
326 errors when the kernel is built as both a driver and as a module
327 and with the following options:
328
329 ADVANSYS_DEBUG - enabled and disabled
330 CONFIG_SMP - enabled and disabled
331 CONFIG_PROC_FS - enabled and disabled
332
333 2. Run tests on an x86, alpha, and PowerPC with at least one narrow
334 card and one wide card attached to a hard disk and CD-ROM drive:
335 fdisk, mkfs, fsck, bonnie, copy/compare test from the
336 CD-ROM to the hard drive.
337
338 H. Release History
339
340 BETA-1.0 (12/23/95):
341 First Release
342
343 BETA-1.1 (12/28/95):
344 1. Prevent advansys_detect() from being called twice.
345 2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'.
346
347 1.2 (1/12/96):
348 1. Prevent re-entrancy in the interrupt handler which
349 resulted in the driver hanging Linux.
350 2. Fix problem that prevented ABP-940 cards from being
351 recognized on some PCI motherboards.
352 3. Add support for the ABP-5140 PnP ISA card.
353 4. Fix check condition return status.
354 5. Add conditionally compiled code for Linux v1.3.X.
355
356 1.3 (2/23/96):
357 1. Fix problem in advansys_biosparam() that resulted in the
358 wrong drive geometry being returned for drives > 1GB with
359 extended translation enabled.
360 2. Add additional tracing during device initialization.
361 3. Change code that only applies to ISA PnP adapter.
362 4. Eliminate 'make dep' warning.
363 5. Try to fix problem with handling resets by increasing their
364 timeout value.
365
366 1.4 (5/8/96):
367 1. Change definitions to eliminate conflicts with other subsystems.
368 2. Add versioning code for the shared interrupt changes.
369 3. Eliminate problem in asc_rmqueue() with iterating after removing
370 a request.
371 4. Remove reset request loop problem from the "Known Problems or
372 Issues" section. This problem was isolated and fixed in the
373 mid-level SCSI driver.
374
375 1.5 (8/8/96):
376 1. Add support for ABP-940U (PCI Ultra) adapter.
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700377 2. Add support for IRQ sharing by setting the IRQF_SHARED flag for
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 request_irq and supplying a dev_id pointer to both request_irq()
379 and free_irq().
380 3. In AscSearchIOPortAddr11() restore a call to check_region() which
381 should be used before I/O port probing.
382 4. Fix bug in asc_prt_hex() which resulted in the displaying
383 the wrong data.
384 5. Incorporate miscellaneous Asc Library bug fixes and new microcode.
385 6. Change driver versioning to be specific to each Linux sub-level.
386 7. Change statistics gathering to be per adapter instead of global
387 to the driver.
388 8. Add more information and statistics to the adapter /proc file:
389 /proc/scsi/advansys[0...].
390 9. Remove 'cmd_per_lun' from the "Known Problems or Issues" list.
391 This problem has been addressed with the SCSI mid-level changes
392 made in v1.3.89. The advansys_select_queue_depths() function
393 was added for the v1.3.89 changes.
394
395 1.6 (9/10/96):
396 1. Incorporate miscellaneous Asc Library bug fixes and new microcode.
397
398 1.7 (9/25/96):
399 1. Enable clustering and optimize the setting of the maximum number
400 of scatter gather elements for any particular board. Clustering
401 increases CPU utilization, but results in a relatively larger
402 increase in I/O throughput.
403 2. Improve the performance of the request queuing functions by
404 adding a last pointer to the queue structure.
405 3. Correct problems with reset and abort request handling that
406 could have hung or crashed Linux.
407 4. Add more information to the adapter /proc file:
408 /proc/scsi/advansys[0...].
409 5. Remove the request timeout issue form the driver issues list.
410 6. Miscellaneous documentation additions and changes.
411
412 1.8 (10/4/96):
413 1. Make changes to handle the new v2.1.0 kernel memory mapping
414 in which a kernel virtual address may not be equivalent to its
415 bus or DMA memory address.
416 2. Change abort and reset request handling to make it yet even
417 more robust.
418 3. Try to mitigate request starvation by sending ordered requests
419 to heavily loaded, tag queuing enabled devices.
420 4. Maintain statistics on request response time.
421 5. Add request response time statistics and other information to
422 the adapter /proc file: /proc/scsi/advansys[0...].
423
424 1.9 (10/21/96):
425 1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to
426 make use of mid-level SCSI driver device queue depth flow
427 control mechanism. This will eliminate aborts caused by a
428 device being unable to keep up with requests and eliminate
429 repeat busy or QUEUE FULL status returned by a device.
430 2. Incorporate miscellaneous Asc Library bug fixes.
431 3. To allow the driver to work in kernels with broken module
432 support set 'cmd_per_lun' if the driver is compiled as a
433 module. This change affects kernels v1.3.89 to present.
434 4. Remove PCI BIOS address from the driver banner. The PCI BIOS
435 is relocated by the motherboard BIOS and its new address can
436 not be determined by the driver.
437 5. Add mid-level SCSI queue depth information to the adapter
438 /proc file: /proc/scsi/advansys[0...].
439
440 2.0 (11/14/96):
441 1. Change allocation of global structures used for device
442 initialization to guarantee they are in DMA-able memory.
443 Previously when the driver was loaded as a module these
444 structures might not have been in DMA-able memory, causing
445 device initialization to fail.
446
447 2.1 (12/30/96):
448 1. In advansys_reset(), if the request is a synchronous reset
449 request, even if the request serial number has changed, then
450 complete the request.
451 2. Add Asc Library bug fixes including new microcode.
452 3. Clear inquiry buffer before using it.
453 4. Correct ifdef typo.
454
455 2.2 (1/15/97):
456 1. Add Asc Library bug fixes including new microcode.
457 2. Add synchronous data transfer rate information to the
458 adapter /proc file: /proc/scsi/advansys[0...].
459 3. Change ADVANSYS_DEBUG to be disabled by default. This
460 will reduce the size of the driver image, eliminate execution
461 overhead, and remove unneeded symbols from the kernel symbol
462 space that were previously added by the driver.
463 4. Add new compile-time option ADVANSYS_ASSERT for assertion
464 code that used to be defined within ADVANSYS_DEBUG. This
465 option is enabled by default.
466
467 2.8 (5/26/97):
468 1. Change version number to 2.8 to synchronize the Linux driver
469 version numbering with other AdvanSys drivers.
470 2. Reformat source files without tabs to present the same view
471 of the file to everyone regardless of the editor tab setting
472 being used.
473 3. Add Asc Library bug fixes.
474
475 3.1A (1/8/98):
476 1. Change version number to 3.1 to indicate that support for
477 Ultra-Wide adapters (ABP-940UW) is included in this release.
478 2. Add Asc Library (Narrow Board) bug fixes.
479 3. Report an underrun condition with the host status byte set
480 to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which
481 causes the underrun condition to be ignored. When Linux defines
482 its own DID_UNDERRUN the constant defined in this file can be
483 removed.
484 4. Add patch to AscWaitTixISRDone().
485 5. Add support for up to 16 different AdvanSys host adapter SCSI
486 channels in one system. This allows four cards with four channels
487 to be used in one system.
488
489 3.1B (1/9/98):
490 1. Handle that PCI register base addresses are not always page
491 aligned even though ioremap() requires that the address argument
492 be page aligned.
493
494 3.1C (1/10/98):
495 1. Update latest BIOS version checked for from the /proc file.
496 2. Don't set microcode SDTR variable at initialization. Instead
497 wait until device capabilities have been detected from an Inquiry
498 command.
499
500 3.1D (1/21/98):
501 1. Improve performance when the driver is compiled as module by
502 allowing up to 64 scatter-gather elements instead of 8.
503
504 3.1E (5/1/98):
505 1. Set time delay in AscWaitTixISRDone() to 1000 ms.
506 2. Include SMP locking changes.
507 3. For v2.1.93 and newer kernels use CONFIG_PCI and new PCI BIOS
508 access functions.
509 4. Update board serial number printing.
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700510 5. Try allocating an IRQ both with and without the IRQF_DISABLED
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 flag set to allow IRQ sharing with drivers that do not set
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700512 the IRQF_DISABLED flag. Also display a more descriptive error
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 message if request_irq() fails.
514 6. Update to latest Asc and Adv Libraries.
515
516 3.2A (7/22/99):
517 1. Update Adv Library to 4.16 which includes support for
518 the ASC38C0800 (Ultra2/LVD) IC.
519
520 3.2B (8/23/99):
521 1. Correct PCI compile time option for v2.1.93 and greater
522 kernels, advansys_info() string, and debug compile time
523 option.
524 2. Correct DvcSleepMilliSecond() for v2.1.0 and greater
525 kernels. This caused an LVD detection/BIST problem problem
526 among other things.
527 3. Sort PCI cards by PCI Bus, Slot, Function ascending order
528 to be consistent with the BIOS.
529 4. Update to Asc Library S121 and Adv Library 5.2.
530
531 3.2C (8/24/99):
532 1. Correct PCI card detection bug introduced in 3.2B that
533 prevented PCI cards from being detected in kernels older
534 than v2.1.93.
535
536 3.2D (8/26/99):
537 1. Correct /proc device synchronous speed information display.
538 Also when re-negotiation is pending for a target device
539 note this condition with an * and footnote.
540 2. Correct initialization problem with Ultra-Wide cards that
541 have a pre-3.2 BIOS. A microcode variable changed locations
542 in 3.2 and greater BIOSes which caused WDTR to be attempted
543 erroneously with drives that don't support WDTR.
544
545 3.2E (8/30/99):
546 1. Fix compile error caused by v2.3.13 PCI structure change.
547 2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM
548 checksum error for ISA cards.
549 3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level
550 SCSI changes that it depended on were never included in Linux.
551
552 3.2F (9/3/99):
553 1. Handle new initial function code added in v2.3.16 for all
554 driver versions.
555
556 3.2G (9/8/99):
557 1. Fix PCI board detection in v2.3.13 and greater kernels.
558 2. Fix comiple errors in v2.3.X with debugging enabled.
559
560 3.2H (9/13/99):
561 1. Add 64-bit address, long support for Alpha and UltraSPARC.
562 The driver has been verified to work on an Alpha system.
563 2. Add partial byte order handling support for Power PC and
564 other big-endian platforms. This support has not yet been
565 completed or verified.
566 3. For wide boards replace block zeroing of request and
567 scatter-gather structures with individual field initialization
568 to improve performance.
569 4. Correct and clarify ROM BIOS version detection.
570
571 3.2I (10/8/99):
572 1. Update to Adv Library 5.4.
573 2. Add v2.3.19 underrun reporting to asc_isr_callback() and
574 adv_isr_callback(). Remove DID_UNDERRUN constant and other
575 no longer needed code that previously documented the lack
576 of underrun handling.
577
578 3.2J (10/14/99):
579 1. Eliminate compile errors for v2.0 and earlier kernels.
580
581 3.2K (11/15/99):
582 1. Correct debug compile error in asc_prt_adv_scsi_req_q().
583 2. Update Adv Library to 5.5.
584 3. Add ifdef handling for /proc changes added in v2.3.28.
585 4. Increase Wide board scatter-gather list maximum length to
586 255 when the driver is compiled into the kernel.
587
588 3.2L (11/18/99):
589 1. Fix bug in adv_get_sglist() that caused an assertion failure
590 at line 7475. The reqp->sgblkp pointer must be initialized
591 to NULL in adv_get_sglist().
592
593 3.2M (11/29/99):
594 1. Really fix bug in adv_get_sglist().
595 2. Incorporate v2.3.29 changes into driver.
596
597 3.2N (4/1/00):
598 1. Add CONFIG_ISA ifdef code.
599 2. Include advansys_interrupts_enabled name change patch.
600 3. For >= v2.3.28 use new SCSI error handling with new function
601 advansys_eh_bus_reset(). Don't include an abort function
602 because of base library limitations.
603 4. For >= v2.3.28 use per board lock instead of io_request_lock.
604 5. For >= v2.3.28 eliminate advansys_command() and
605 advansys_command_done().
606 6. Add some changes for PowerPC (Big Endian) support, but it isn't
607 working yet.
608 7. Fix "nonexistent resource free" problem that occurred on a module
609 unload for boards with an I/O space >= 255. The 'n_io_port' field
610 is only one byte and can not be used to hold an ioport length more
611 than 255.
612
613 3.3A (4/4/00):
614 1. Update to Adv Library 5.8.
615 2. For wide cards add support for CDBs up to 16 bytes.
616 3. Eliminate warnings when CONFIG_PROC_FS is not defined.
617
618 3.3B (5/1/00):
619 1. Support for PowerPC (Big Endian) wide cards. Narrow cards
620 still need work.
621 2. Change bitfields to shift and mask access for endian
622 portability.
623
624 3.3C (10/13/00):
625 1. Update for latest 2.4 kernel.
626 2. Test ABP-480 CardBus support in 2.4 kernel - works!
627 3. Update to Asc Library S123.
628 4. Update to Adv Library 5.12.
629
630 3.3D (11/22/00):
631 1. Update for latest 2.4 kernel.
632 2. Create patches for 2.2 and 2.4 kernels.
633
634 3.3E (1/9/01):
635 1. Now that 2.4 is released remove ifdef code for kernel versions
636 less than 2.2. The driver is now only supported in kernels 2.2,
637 2.4, and greater.
638 2. Add code to release and acquire the io_request_lock in
639 the driver entrypoint functions: advansys_detect and
640 advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver
641 still holds the io_request_lock on entry to SCSI low-level drivers.
642 This was supposed to be removed before 2.4 was released but never
643 happened. When the mid-level SCSI driver is changed all references
644 to the io_request_lock should be removed from the driver.
645 3. Simplify error handling by removing advansys_abort(),
646 AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are
647 now handled by resetting the SCSI bus and fully re-initializing
648 the chip. This simple method of error recovery has proven to work
649 most reliably after attempts at different methods. Also now only
650 support the "new" error handling method and remove the obsolete
651 error handling interface.
652 4. Fix debug build errors.
653
654 3.3F (1/24/01):
655 1. Merge with ConnectCom version from Andy Kellner which
656 updates Adv Library to 5.14.
657 2. Make PowerPC (Big Endian) work for narrow cards and
658 fix problems writing EEPROM for wide cards.
659 3. Remove interrupts_enabled assertion function.
660
661 3.3G (2/16/01):
662 1. Return an error from narrow boards if passed a 16 byte
663 CDB. The wide board can already handle 16 byte CDBs.
664
665 3.3GJ (4/15/02):
666 1. hacks for lk 2.5 series (D. Gilbert)
667
668 3.3GJD (10/14/02):
669 1. change select_queue_depths to slave_configure
670 2. make cmd_per_lun be sane again
671
672 3.3K [2004/06/24]:
673 1. continuing cleanup for lk 2.6 series
674 2. Fix problem in lk 2.6.7-bk2 that broke PCI wide cards
675 3. Fix problem that oopsed ISA cards
676
677 I. Known Problems/Fix List (XXX)
678
679 1. Need to add memory mapping workaround. Test the memory mapping.
680 If it doesn't work revert to I/O port access. Can a test be done
681 safely?
682 2. Handle an interrupt not working. Keep an interrupt counter in
683 the interrupt handler. In the timeout function if the interrupt
684 has not occurred then print a message and run in polled mode.
685 3. Allow bus type scanning order to be changed.
686 4. Need to add support for target mode commands, cf. CAM XPT.
687
688 J. Credits (Chronological Order)
689
690 Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver
691 and maintained it up to 3.3F. He continues to answer questions
692 and help maintain the driver.
693
694 Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
695 basis for the Linux v1.3.X changes which were included in the
696 1.2 release.
697
698 Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
699 in advansys_biosparam() which was fixed in the 1.3 release.
700
701 Erik Ratcliffe <erik@caldera.com> has done testing of the
702 AdvanSys driver in the Caldera releases.
703
704 Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
705 AscWaitTixISRDone() which he found necessary to make the
706 driver work with a SCSI-1 disk.
707
708 Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
709 support in the 3.1A driver.
710
711 Doug Gilbert <dgilbert@interlog.com> has made changes and
712 suggestions to improve the driver and done a lot of testing.
713
714 Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
715 in 3.2K.
716
717 Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
718 patch and helped with PowerPC wide and narrow board support.
719
720 Philip Blundell <philb@gnu.org> provided an
721 advansys_interrupts_enabled patch.
722
723 Dave Jones <dave@denial.force9.co.uk> reported the compiler
724 warnings generated when CONFIG_PROC_FS was not defined in
725 the 3.2M driver.
726
727 Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian
728 problems) for wide cards.
729
730 Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow
731 card error handling.
732
733 Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow
734 board support and fixed a bug in AscGetEEPConfig().
735
736 Arnaldo Carvalho de Melo <acme@conectiva.com.br> made
737 save_flags/restore_flags changes.
738
739 Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI
740 driver development for ConnectCom (Version > 3.3F).
741
742 K. ConnectCom (AdvanSys) Contact Information
743
744 Mail: ConnectCom Solutions, Inc.
745 1150 Ringwood Court
746 San Jose, CA 95131
747 Operator/Sales: 1-408-383-9400
748 FAX: 1-408-383-9612
749 Tech Support: 1-408-467-2930
750 Tech Support E-Mail: linux@connectcom.net
751 FTP Site: ftp.connectcom.net (login: anonymous)
752 Web Site: http://www.connectcom.net
753
754*/
755
756/*
757 * --- Linux Include Files
758 */
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761#include <linux/string.h>
762#include <linux/kernel.h>
763#include <linux/types.h>
764#include <linux/ioport.h>
765#include <linux/interrupt.h>
766#include <linux/delay.h>
767#include <linux/slab.h>
768#include <linux/mm.h>
769#include <linux/proc_fs.h>
770#include <linux/init.h>
771#include <linux/blkdev.h>
Matthew Wilcoxc304ec92007-07-30 09:18:45 -0600772#include <linux/isa.h>
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -0600773#include <linux/eisa.h>
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -0400774#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775#include <linux/spinlock.h>
776#include <linux/dma-mapping.h>
777
778#include <asm/io.h>
779#include <asm/system.h>
780#include <asm/dma.h>
781
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -0400782#include <scsi/scsi_cmnd.h>
783#include <scsi/scsi_device.h>
784#include <scsi/scsi_tcq.h>
785#include <scsi/scsi.h>
786#include <scsi/scsi_host.h>
787
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -0600788/* FIXME: (by jejb@steeleye.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 *
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -0600790 * Although all of the necessary command mapping places have the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 * appropriate dma_map.. APIs, the driver still processes its internal
792 * queue using bus_to_virt() and virt_to_bus() which are illegal under
793 * the API. The entire queue processing structure will need to be
794 * altered to fix this.
795 */
796#warning this driver is still not properly converted to the DMA API
797
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798/*
799 * --- Driver Options
800 */
801
802/* Enable driver assertions. */
803#define ADVANSYS_ASSERT
804
805/* Enable driver /proc statistics. */
806#define ADVANSYS_STATS
807
808/* Enable driver tracing. */
809/* #define ADVANSYS_DEBUG */
810
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811/*
812 * --- Asc Library Constants and Macros
813 */
814
815#define ASC_LIB_VERSION_MAJOR 1
816#define ASC_LIB_VERSION_MINOR 24
817#define ASC_LIB_SERIAL_NUMBER 123
818
819/*
820 * Portable Data Types
821 *
822 * Any instance where a 32-bit long or pointer type is assumed
823 * for precision or HW defined structures, the following define
824 * types must be used. In Linux the char, short, and int types
825 * are all consistent at 8, 16, and 32 bits respectively. Pointers
826 * and long types are 64 bits on Alpha and UltraSPARC.
827 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400828#define ASC_PADDR __u32 /* Physical/Bus address data type. */
829#define ASC_VADDR __u32 /* Virtual address data type. */
830#define ASC_DCNT __u32 /* Unsigned Data count type. */
831#define ASC_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833/*
834 * These macros are used to convert a virtual address to a
835 * 32-bit value. This currently can be used on Linux Alpha
836 * which uses 64-bit virtual address but a 32-bit bus address.
837 * This is likely to break in the future, but doing this now
838 * will give us time to change the HW and FW to handle 64-bit
839 * addresses.
840 */
841#define ASC_VADDR_TO_U32 virt_to_bus
842#define ASC_U32_TO_VADDR bus_to_virt
843
844typedef unsigned char uchar;
845
846#ifndef TRUE
847#define TRUE (1)
848#endif
849#ifndef FALSE
850#define FALSE (0)
851#endif
852
853#define EOF (-1)
854#define ERR (-1)
855#define UW_ERR (uint)(0xFFFF)
856#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
858#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
860#define ASC_DVCLIB_CALL_DONE (1)
861#define ASC_DVCLIB_CALL_FAILED (0)
862#define ASC_DVCLIB_CALL_ERROR (-1)
863
Dave Jones2672ea82006-08-02 17:11:49 -0400864#define PCI_VENDOR_ID_ASP 0x10cd
865#define PCI_DEVICE_ID_ASP_1200A 0x1100
866#define PCI_DEVICE_ID_ASP_ABP940 0x1200
867#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
868#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
869#define PCI_DEVICE_ID_38C0800_REV1 0x2500
870#define PCI_DEVICE_ID_38C1600_REV1 0x2700
871
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872/*
873 * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
874 * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
875 * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
876 * SRB structure.
877 */
878#define CC_VERY_LONG_SG_LIST 0
879#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr)
880
Matthew Wilcox27c868c2007-07-26 10:56:23 -0400881#define PortAddr unsigned short /* port address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882#define inp(port) inb(port)
883#define outp(port, byte) outb((byte), (port))
884
885#define inpw(port) inw(port)
886#define outpw(port, word) outw((word), (port))
887
888#define ASC_MAX_SG_QUEUE 7
889#define ASC_MAX_SG_LIST 255
890
891#define ASC_CS_TYPE unsigned short
892
893#define ASC_IS_ISA (0x0001)
894#define ASC_IS_ISAPNP (0x0081)
895#define ASC_IS_EISA (0x0002)
896#define ASC_IS_PCI (0x0004)
897#define ASC_IS_PCI_ULTRA (0x0104)
898#define ASC_IS_PCMCIA (0x0008)
899#define ASC_IS_MCA (0x0020)
900#define ASC_IS_VL (0x0040)
901#define ASC_ISA_PNP_PORT_ADDR (0x279)
902#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
903#define ASC_IS_WIDESCSI_16 (0x0100)
904#define ASC_IS_WIDESCSI_32 (0x0200)
905#define ASC_IS_BIG_ENDIAN (0x8000)
906#define ASC_CHIP_MIN_VER_VL (0x01)
907#define ASC_CHIP_MAX_VER_VL (0x07)
908#define ASC_CHIP_MIN_VER_PCI (0x09)
909#define ASC_CHIP_MAX_VER_PCI (0x0F)
910#define ASC_CHIP_VER_PCI_BIT (0x08)
911#define ASC_CHIP_MIN_VER_ISA (0x11)
912#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
913#define ASC_CHIP_MAX_VER_ISA (0x27)
914#define ASC_CHIP_VER_ISA_BIT (0x30)
915#define ASC_CHIP_VER_ISAPNP_BIT (0x20)
916#define ASC_CHIP_VER_ASYN_BUG (0x21)
917#define ASC_CHIP_VER_PCI 0x08
918#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02)
919#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03)
920#define ASC_CHIP_MIN_VER_EISA (0x41)
921#define ASC_CHIP_MAX_VER_EISA (0x47)
922#define ASC_CHIP_VER_EISA_BIT (0x40)
923#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
924#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER 0x21
925#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER 0x0A
926#define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL)
927#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL)
928#define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL)
929#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL)
930#define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL)
931#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
932#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
933#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
934
935#define ASC_SCSI_ID_BITS 3
936#define ASC_SCSI_TIX_TYPE uchar
937#define ASC_ALL_DEVICE_BIT_SET 0xFF
938#define ASC_SCSI_BIT_ID_TYPE uchar
939#define ASC_MAX_TID 7
940#define ASC_MAX_LUN 7
941#define ASC_SCSI_WIDTH_BIT_SET 0xFF
942#define ASC_MAX_SENSE_LEN 32
943#define ASC_MIN_SENSE_LEN 14
944#define ASC_MAX_CDB_LEN 12
945#define ASC_SCSI_RESET_HOLD_TIME_US 60
946
947#define ADV_INQ_CLOCKING_ST_ONLY 0x0
948#define ADV_INQ_CLOCKING_DT_ONLY 0x1
949#define ADV_INQ_CLOCKING_ST_AND_DT 0x3
950
951/*
952 * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
953 * and CmdDt (Command Support Data) field bit definitions.
954 */
955#define ADV_INQ_RTN_VPD_AND_CMDDT 0x3
956#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE 0x2
957#define ADV_INQ_RTN_VPD_FOR_PG_CODE 0x1
958#define ADV_INQ_RTN_STD_INQUIRY_DATA 0x0
959
960#define ASC_SCSIDIR_NOCHK 0x00
961#define ASC_SCSIDIR_T2H 0x08
962#define ASC_SCSIDIR_H2T 0x10
963#define ASC_SCSIDIR_NODATA 0x18
964#define SCSI_ASC_NOMEDIA 0x3A
965#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
966#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
967#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
968#define PUT_CDB1(x) ((uchar)((uint)(x) >> 8))
969#define MS_CMD_DONE 0x00
970#define MS_EXTEND 0x01
971#define MS_SDTR_LEN 0x03
972#define MS_SDTR_CODE 0x01
973#define MS_WDTR_LEN 0x02
974#define MS_WDTR_CODE 0x03
975#define MS_MDP_LEN 0x05
976#define MS_MDP_CODE 0x00
977
978/*
979 * Inquiry data structure and bitfield macros
980 *
981 * Only quantities of more than 1 bit are shifted, since the others are
982 * just tested for true or false. C bitfields aren't portable between big
983 * and little-endian platforms so they are not used.
984 */
985
986#define ASC_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
987#define ASC_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
988#define ASC_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
989#define ASC_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
990#define ASC_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
991#define ASC_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
992#define ASC_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
993#define ASC_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
994#define ASC_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
995#define ASC_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
996#define ASC_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
997#define ASC_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
998#define ASC_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
999#define ASC_INQ_SYNC(inq) ((inq)->flags & 0x10)
1000#define ASC_INQ_WIDE16(inq) ((inq)->flags & 0x20)
1001#define ASC_INQ_WIDE32(inq) ((inq)->flags & 0x40)
1002#define ASC_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
1003#define ASC_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
1004#define ASC_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
1005#define ASC_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
1006
1007typedef struct {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001008 uchar periph;
1009 uchar devtype;
1010 uchar ver;
1011 uchar byte3;
1012 uchar add_len;
1013 uchar res1;
1014 uchar res2;
1015 uchar flags;
1016 uchar vendor_id[8];
1017 uchar product_id[16];
1018 uchar product_rev_level[4];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019} ASC_SCSI_INQUIRY;
1020
1021#define ASC_SG_LIST_PER_Q 7
1022#define QS_FREE 0x00
1023#define QS_READY 0x01
1024#define QS_DISC1 0x02
1025#define QS_DISC2 0x04
1026#define QS_BUSY 0x08
1027#define QS_ABORTED 0x40
1028#define QS_DONE 0x80
1029#define QC_NO_CALLBACK 0x01
1030#define QC_SG_SWAP_QUEUE 0x02
1031#define QC_SG_HEAD 0x04
1032#define QC_DATA_IN 0x08
1033#define QC_DATA_OUT 0x10
1034#define QC_URGENT 0x20
1035#define QC_MSG_OUT 0x40
1036#define QC_REQ_SENSE 0x80
1037#define QCSG_SG_XFER_LIST 0x02
1038#define QCSG_SG_XFER_MORE 0x04
1039#define QCSG_SG_XFER_END 0x08
1040#define QD_IN_PROGRESS 0x00
1041#define QD_NO_ERROR 0x01
1042#define QD_ABORTED_BY_HOST 0x02
1043#define QD_WITH_ERROR 0x04
1044#define QD_INVALID_REQUEST 0x80
1045#define QD_INVALID_HOST_NUM 0x81
1046#define QD_INVALID_DEVICE 0x82
1047#define QD_ERR_INTERNAL 0xFF
1048#define QHSTA_NO_ERROR 0x00
1049#define QHSTA_M_SEL_TIMEOUT 0x11
1050#define QHSTA_M_DATA_OVER_RUN 0x12
1051#define QHSTA_M_DATA_UNDER_RUN 0x12
1052#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
1053#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14
1054#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
1055#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22
1056#define QHSTA_D_HOST_ABORT_FAILED 0x23
1057#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24
1058#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
1059#define QHSTA_D_ASPI_NO_BUF_POOL 0x26
1060#define QHSTA_M_WTM_TIMEOUT 0x41
1061#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
1062#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
1063#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
1064#define QHSTA_M_TARGET_STATUS_BUSY 0x45
1065#define QHSTA_M_BAD_TAG_CODE 0x46
1066#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47
1067#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
1068#define QHSTA_D_LRAM_CMP_ERROR 0x81
1069#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
1070#define ASC_FLAG_SCSIQ_REQ 0x01
1071#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02
1072#define ASC_FLAG_BIOS_ASYNC_IO 0x04
1073#define ASC_FLAG_SRB_LINEAR_ADDR 0x08
1074#define ASC_FLAG_WIN16 0x10
1075#define ASC_FLAG_WIN32 0x20
1076#define ASC_FLAG_ISA_OVER_16MB 0x40
1077#define ASC_FLAG_DOS_VM_CALLBACK 0x80
1078#define ASC_TAG_FLAG_EXTRA_BYTES 0x10
1079#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04
1080#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08
1081#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
1082#define ASC_SCSIQ_CPY_BEG 4
1083#define ASC_SCSIQ_SGHD_CPY_BEG 2
1084#define ASC_SCSIQ_B_FWD 0
1085#define ASC_SCSIQ_B_BWD 1
1086#define ASC_SCSIQ_B_STATUS 2
1087#define ASC_SCSIQ_B_QNO 3
1088#define ASC_SCSIQ_B_CNTL 4
1089#define ASC_SCSIQ_B_SG_QUEUE_CNT 5
1090#define ASC_SCSIQ_D_DATA_ADDR 8
1091#define ASC_SCSIQ_D_DATA_CNT 12
1092#define ASC_SCSIQ_B_SENSE_LEN 20
1093#define ASC_SCSIQ_DONE_INFO_BEG 22
1094#define ASC_SCSIQ_D_SRBPTR 22
1095#define ASC_SCSIQ_B_TARGET_IX 26
1096#define ASC_SCSIQ_B_CDB_LEN 28
1097#define ASC_SCSIQ_B_TAG_CODE 29
1098#define ASC_SCSIQ_W_VM_ID 30
1099#define ASC_SCSIQ_DONE_STATUS 32
1100#define ASC_SCSIQ_HOST_STATUS 33
1101#define ASC_SCSIQ_SCSI_STATUS 34
1102#define ASC_SCSIQ_CDB_BEG 36
1103#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
1104#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60
1105#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48
1106#define ASC_SCSIQ_B_SG_WK_QP 49
1107#define ASC_SCSIQ_B_SG_WK_IX 50
1108#define ASC_SCSIQ_W_ALT_DC1 52
1109#define ASC_SCSIQ_B_LIST_CNT 6
1110#define ASC_SCSIQ_B_CUR_LIST_CNT 7
1111#define ASC_SGQ_B_SG_CNTL 4
1112#define ASC_SGQ_B_SG_HEAD_QP 5
1113#define ASC_SGQ_B_SG_LIST_CNT 6
1114#define ASC_SGQ_B_SG_CUR_LIST_CNT 7
1115#define ASC_SGQ_LIST_BEG 8
1116#define ASC_DEF_SCSI1_QNG 4
1117#define ASC_MAX_SCSI1_QNG 4
1118#define ASC_DEF_SCSI2_QNG 16
1119#define ASC_MAX_SCSI2_QNG 32
1120#define ASC_TAG_CODE_MASK 0x23
1121#define ASC_STOP_REQ_RISC_STOP 0x01
1122#define ASC_STOP_ACK_RISC_STOP 0x03
1123#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10
1124#define ASC_STOP_CLEAN_UP_DISC_Q 0x20
1125#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
1126#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
1127#define ASC_TID_TO_TARGET_ID(tid) (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
1128#define ASC_TIX_TO_TARGET_ID(tix) (0x01 << ((tix) & ASC_MAX_TID))
1129#define ASC_TIX_TO_TID(tix) ((tix) & ASC_MAX_TID)
1130#define ASC_TID_TO_TIX(tid) ((tid) & ASC_MAX_TID)
1131#define ASC_TIX_TO_LUN(tix) (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
1132#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6))
1133
1134typedef struct asc_scsiq_1 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001135 uchar status;
1136 uchar q_no;
1137 uchar cntl;
1138 uchar sg_queue_cnt;
1139 uchar target_id;
1140 uchar target_lun;
1141 ASC_PADDR data_addr;
1142 ASC_DCNT data_cnt;
1143 ASC_PADDR sense_addr;
1144 uchar sense_len;
1145 uchar extra_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146} ASC_SCSIQ_1;
1147
1148typedef struct asc_scsiq_2 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001149 ASC_VADDR srb_ptr;
1150 uchar target_ix;
1151 uchar flag;
1152 uchar cdb_len;
1153 uchar tag_code;
1154 ushort vm_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155} ASC_SCSIQ_2;
1156
1157typedef struct asc_scsiq_3 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001158 uchar done_stat;
1159 uchar host_stat;
1160 uchar scsi_stat;
1161 uchar scsi_msg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162} ASC_SCSIQ_3;
1163
1164typedef struct asc_scsiq_4 {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001165 uchar cdb[ASC_MAX_CDB_LEN];
1166 uchar y_first_sg_list_qp;
1167 uchar y_working_sg_qp;
1168 uchar y_working_sg_ix;
1169 uchar y_res;
1170 ushort x_req_count;
1171 ushort x_reconnect_rtn;
1172 ASC_PADDR x_saved_data_addr;
1173 ASC_DCNT x_saved_data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174} ASC_SCSIQ_4;
1175
1176typedef struct asc_q_done_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001177 ASC_SCSIQ_2 d2;
1178 ASC_SCSIQ_3 d3;
1179 uchar q_status;
1180 uchar q_no;
1181 uchar cntl;
1182 uchar sense_len;
1183 uchar extra_bytes;
1184 uchar res;
1185 ASC_DCNT remain_bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186} ASC_QDONE_INFO;
1187
1188typedef struct asc_sg_list {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001189 ASC_PADDR addr;
1190 ASC_DCNT bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191} ASC_SG_LIST;
1192
1193typedef struct asc_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001194 ushort entry_cnt;
1195 ushort queue_cnt;
1196 ushort entry_to_copy;
1197 ushort res;
1198 ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199} ASC_SG_HEAD;
1200
1201#define ASC_MIN_SG_LIST 2
1202
1203typedef struct asc_min_sg_head {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001204 ushort entry_cnt;
1205 ushort queue_cnt;
1206 ushort entry_to_copy;
1207 ushort res;
1208 ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209} ASC_MIN_SG_HEAD;
1210
1211#define QCX_SORT (0x0001)
1212#define QCX_COALEASE (0x0002)
1213
1214typedef struct asc_scsi_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001215 ASC_SCSIQ_1 q1;
1216 ASC_SCSIQ_2 q2;
1217 uchar *cdbptr;
1218 ASC_SG_HEAD *sg_head;
1219 ushort remain_sg_entry_cnt;
1220 ushort next_sg_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221} ASC_SCSI_Q;
1222
1223typedef struct asc_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001224 ASC_SCSIQ_1 r1;
1225 ASC_SCSIQ_2 r2;
1226 uchar *cdbptr;
1227 ASC_SG_HEAD *sg_head;
1228 uchar *sense_ptr;
1229 ASC_SCSIQ_3 r3;
1230 uchar cdb[ASC_MAX_CDB_LEN];
1231 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232} ASC_SCSI_REQ_Q;
1233
1234typedef struct asc_scsi_bios_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001235 ASC_SCSIQ_1 r1;
1236 ASC_SCSIQ_2 r2;
1237 uchar *cdbptr;
1238 ASC_SG_HEAD *sg_head;
1239 uchar *sense_ptr;
1240 ASC_SCSIQ_3 r3;
1241 uchar cdb[ASC_MAX_CDB_LEN];
1242 uchar sense[ASC_MIN_SENSE_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243} ASC_SCSI_BIOS_REQ_Q;
1244
1245typedef struct asc_risc_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001246 uchar fwd;
1247 uchar bwd;
1248 ASC_SCSIQ_1 i1;
1249 ASC_SCSIQ_2 i2;
1250 ASC_SCSIQ_3 i3;
1251 ASC_SCSIQ_4 i4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252} ASC_RISC_Q;
1253
1254typedef struct asc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001255 uchar seq_no;
1256 uchar q_no;
1257 uchar cntl;
1258 uchar sg_head_qp;
1259 uchar sg_list_cnt;
1260 uchar sg_cur_list_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261} ASC_SG_LIST_Q;
1262
1263typedef struct asc_risc_sg_list_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001264 uchar fwd;
1265 uchar bwd;
1266 ASC_SG_LIST_Q sg;
1267 ASC_SG_LIST sg_list[7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268} ASC_RISC_SG_LIST_Q;
1269
1270#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL
1271#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024
1272#define ASCQ_ERR_NO_ERROR 0
1273#define ASCQ_ERR_IO_NOT_FOUND 1
1274#define ASCQ_ERR_LOCAL_MEM 2
1275#define ASCQ_ERR_CHKSUM 3
1276#define ASCQ_ERR_START_CHIP 4
1277#define ASCQ_ERR_INT_TARGET_ID 5
1278#define ASCQ_ERR_INT_LOCAL_MEM 6
1279#define ASCQ_ERR_HALT_RISC 7
1280#define ASCQ_ERR_GET_ASPI_ENTRY 8
1281#define ASCQ_ERR_CLOSE_ASPI 9
1282#define ASCQ_ERR_HOST_INQUIRY 0x0A
1283#define ASCQ_ERR_SAVED_SRB_BAD 0x0B
1284#define ASCQ_ERR_QCNTL_SG_LIST 0x0C
1285#define ASCQ_ERR_Q_STATUS 0x0D
1286#define ASCQ_ERR_WR_SCSIQ 0x0E
1287#define ASCQ_ERR_PC_ADDR 0x0F
1288#define ASCQ_ERR_SYN_OFFSET 0x10
1289#define ASCQ_ERR_SYN_XFER_TIME 0x11
1290#define ASCQ_ERR_LOCK_DMA 0x12
1291#define ASCQ_ERR_UNLOCK_DMA 0x13
1292#define ASCQ_ERR_VDS_CHK_INSTALL 0x14
1293#define ASCQ_ERR_MICRO_CODE_HALT 0x15
1294#define ASCQ_ERR_SET_LRAM_ADDR 0x16
1295#define ASCQ_ERR_CUR_QNG 0x17
1296#define ASCQ_ERR_SG_Q_LINKS 0x18
1297#define ASCQ_ERR_SCSIQ_PTR 0x19
1298#define ASCQ_ERR_ISR_RE_ENTRY 0x1A
1299#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B
1300#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C
1301#define ASCQ_ERR_SG_LIST_ODD_ADDRESS 0x1D
1302#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
1303#define ASCQ_ERR_SCSIQ_NULL_PTR 0x1F
1304#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR 0x20
1305#define ASCQ_ERR_GET_NUM_OF_FREE_Q 0x21
1306#define ASCQ_ERR_SEND_SCSI_Q 0x22
1307#define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23
1308#define ASCQ_ERR_RESET_SDTR 0x24
1309
1310/*
1311 * Warning code values are set in ASC_DVC_VAR 'warn_code'.
1312 */
1313#define ASC_WARN_NO_ERROR 0x0000
1314#define ASC_WARN_IO_PORT_ROTATE 0x0001
1315#define ASC_WARN_EEPROM_CHKSUM 0x0002
1316#define ASC_WARN_IRQ_MODIFIED 0x0004
1317#define ASC_WARN_AUTO_CONFIG 0x0008
1318#define ASC_WARN_CMD_QNG_CONFLICT 0x0010
1319#define ASC_WARN_EEPROM_RECOVER 0x0020
1320#define ASC_WARN_CFG_MSW_RECOVER 0x0040
1321#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
1322
1323/*
1324 * Error code values are set in ASC_DVC_VAR 'err_code'.
1325 */
1326#define ASC_IERR_WRITE_EEPROM 0x0001
1327#define ASC_IERR_MCODE_CHKSUM 0x0002
1328#define ASC_IERR_SET_PC_ADDR 0x0004
1329#define ASC_IERR_START_STOP_CHIP 0x0008
1330#define ASC_IERR_IRQ_NO 0x0010
1331#define ASC_IERR_SET_IRQ_NO 0x0020
1332#define ASC_IERR_CHIP_VERSION 0x0040
1333#define ASC_IERR_SET_SCSI_ID 0x0080
1334#define ASC_IERR_GET_PHY_ADDR 0x0100
1335#define ASC_IERR_BAD_SIGNATURE 0x0200
1336#define ASC_IERR_NO_BUS_TYPE 0x0400
1337#define ASC_IERR_SCAM 0x0800
1338#define ASC_IERR_SET_SDTR 0x1000
1339#define ASC_IERR_RW_LRAM 0x8000
1340
1341#define ASC_DEF_IRQ_NO 10
1342#define ASC_MAX_IRQ_NO 15
1343#define ASC_MIN_IRQ_NO 10
1344#define ASC_MIN_REMAIN_Q (0x02)
1345#define ASC_DEF_MAX_TOTAL_QNG (0xF0)
1346#define ASC_MIN_TAG_Q_PER_DVC (0x04)
1347#define ASC_DEF_TAG_Q_PER_DVC (0x04)
1348#define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q
1349#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
1350#define ASC_MAX_TOTAL_QNG 240
1351#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
1352#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8
1353#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20
1354#define ASC_MAX_INRAM_TAG_QNG 16
1355#define ASC_IOADR_TABLE_MAX_IX 11
1356#define ASC_IOADR_GAP 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357#define ASC_LIB_SCSIQ_WK_SP 256
1358#define ASC_MAX_SYN_XFER_NO 16
1359#define ASC_SYN_MAX_OFFSET 0x0F
1360#define ASC_DEF_SDTR_OFFSET 0x0F
1361#define ASC_DEF_SDTR_INDEX 0x00
1362#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02
1363#define SYN_XFER_NS_0 25
1364#define SYN_XFER_NS_1 30
1365#define SYN_XFER_NS_2 35
1366#define SYN_XFER_NS_3 40
1367#define SYN_XFER_NS_4 50
1368#define SYN_XFER_NS_5 60
1369#define SYN_XFER_NS_6 70
1370#define SYN_XFER_NS_7 85
1371#define SYN_ULTRA_XFER_NS_0 12
1372#define SYN_ULTRA_XFER_NS_1 19
1373#define SYN_ULTRA_XFER_NS_2 25
1374#define SYN_ULTRA_XFER_NS_3 32
1375#define SYN_ULTRA_XFER_NS_4 38
1376#define SYN_ULTRA_XFER_NS_5 44
1377#define SYN_ULTRA_XFER_NS_6 50
1378#define SYN_ULTRA_XFER_NS_7 57
1379#define SYN_ULTRA_XFER_NS_8 63
1380#define SYN_ULTRA_XFER_NS_9 69
1381#define SYN_ULTRA_XFER_NS_10 75
1382#define SYN_ULTRA_XFER_NS_11 82
1383#define SYN_ULTRA_XFER_NS_12 88
1384#define SYN_ULTRA_XFER_NS_13 94
1385#define SYN_ULTRA_XFER_NS_14 100
1386#define SYN_ULTRA_XFER_NS_15 107
1387
1388typedef struct ext_msg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001389 uchar msg_type;
1390 uchar msg_len;
1391 uchar msg_req;
1392 union {
1393 struct {
1394 uchar sdtr_xfer_period;
1395 uchar sdtr_req_ack_offset;
1396 } sdtr;
1397 struct {
1398 uchar wdtr_width;
1399 } wdtr;
1400 struct {
1401 uchar mdp_b3;
1402 uchar mdp_b2;
1403 uchar mdp_b1;
1404 uchar mdp_b0;
1405 } mdp;
1406 } u_ext_msg;
1407 uchar res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408} EXT_MSG;
1409
1410#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period
1411#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset
1412#define wdtr_width u_ext_msg.wdtr.wdtr_width
1413#define mdp_b3 u_ext_msg.mdp_b3
1414#define mdp_b2 u_ext_msg.mdp_b2
1415#define mdp_b1 u_ext_msg.mdp_b1
1416#define mdp_b0 u_ext_msg.mdp_b0
1417
1418typedef struct asc_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001419 ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
1420 ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
1421 ASC_SCSI_BIT_ID_TYPE disc_enable;
1422 ASC_SCSI_BIT_ID_TYPE sdtr_enable;
1423 uchar chip_scsi_id;
1424 uchar isa_dma_speed;
1425 uchar isa_dma_channel;
1426 uchar chip_version;
1427 ushort lib_serial_no;
1428 ushort lib_version;
1429 ushort mcode_date;
1430 ushort mcode_version;
1431 uchar max_tag_qng[ASC_MAX_TID + 1];
1432 uchar *overrun_buf;
1433 uchar sdtr_period_offset[ASC_MAX_TID + 1];
1434 ushort pci_slot_info;
1435 uchar adapter_info[6];
1436 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437} ASC_DVC_CFG;
1438
1439#define ASC_DEF_DVC_CNTL 0xFFFF
1440#define ASC_DEF_CHIP_SCSI_ID 7
1441#define ASC_DEF_ISA_DMA_SPEED 4
1442#define ASC_INIT_STATE_NULL 0x0000
1443#define ASC_INIT_STATE_BEG_GET_CFG 0x0001
1444#define ASC_INIT_STATE_END_GET_CFG 0x0002
1445#define ASC_INIT_STATE_BEG_SET_CFG 0x0004
1446#define ASC_INIT_STATE_END_SET_CFG 0x0008
1447#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010
1448#define ASC_INIT_STATE_END_LOAD_MC 0x0020
1449#define ASC_INIT_STATE_BEG_INQUIRY 0x0040
1450#define ASC_INIT_STATE_END_INQUIRY 0x0080
1451#define ASC_INIT_RESET_SCSI_DONE 0x0100
1452#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
1454#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
1455#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
1456#define ASC_MIN_TAGGED_CMD 7
1457#define ASC_MAX_SCSI_RESET_WAIT 30
1458
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001459struct asc_dvc_var; /* Forward Declaration. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001461typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
1462typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463
1464typedef struct asc_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001465 PortAddr iop_base;
1466 ushort err_code;
1467 ushort dvc_cntl;
1468 ushort bug_fix_cntl;
1469 ushort bus_type;
1470 ASC_ISR_CALLBACK isr_callback;
1471 ASC_EXE_CALLBACK exe_callback;
1472 ASC_SCSI_BIT_ID_TYPE init_sdtr;
1473 ASC_SCSI_BIT_ID_TYPE sdtr_done;
1474 ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
1475 ASC_SCSI_BIT_ID_TYPE unit_not_ready;
1476 ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
1477 ASC_SCSI_BIT_ID_TYPE start_motor;
1478 uchar scsi_reset_wait;
1479 uchar chip_no;
1480 char is_in_int;
1481 uchar max_total_qng;
1482 uchar cur_total_qng;
1483 uchar in_critical_cnt;
1484 uchar irq_no;
1485 uchar last_q_shortage;
1486 ushort init_state;
1487 uchar cur_dvc_qng[ASC_MAX_TID + 1];
1488 uchar max_dvc_qng[ASC_MAX_TID + 1];
1489 ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
1490 ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
1491 uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
1492 ASC_DVC_CFG *cfg;
1493 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
1494 char redo_scam;
1495 ushort res2;
1496 uchar dos_int13_table[ASC_MAX_TID + 1];
1497 ASC_DCNT max_dma_count;
1498 ASC_SCSI_BIT_ID_TYPE no_scam;
1499 ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
1500 uchar max_sdtr_index;
1501 uchar host_init_sdtr_index;
1502 struct asc_board *drv_ptr;
1503 ASC_DCNT uc_break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504} ASC_DVC_VAR;
1505
1506typedef struct asc_dvc_inq_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001507 uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508} ASC_DVC_INQ_INFO;
1509
1510typedef struct asc_cap_info {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001511 ASC_DCNT lba;
1512 ASC_DCNT blk_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513} ASC_CAP_INFO;
1514
1515typedef struct asc_cap_info_array {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001516 ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517} ASC_CAP_INFO_ARRAY;
1518
1519#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001
1520#define ASC_MCNTL_NULL_TARGET (ushort)0x0002
1521#define ASC_CNTL_INITIATOR (ushort)0x0001
1522#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002
1523#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004
1524#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008
1525#define ASC_CNTL_NO_SCAM (ushort)0x0010
1526#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080
1527#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040
1528#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100
1529#define ASC_CNTL_RESET_SCSI (ushort)0x0200
1530#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400
1531#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800
1532#define ASC_CNTL_SCSI_PARITY (ushort)0x1000
1533#define ASC_CNTL_BURST_MODE (ushort)0x2000
1534#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
1535#define ASC_EEP_DVC_CFG_BEG_VL 2
1536#define ASC_EEP_MAX_DVC_ADDR_VL 15
1537#define ASC_EEP_DVC_CFG_BEG 32
1538#define ASC_EEP_MAX_DVC_ADDR 45
1539#define ASC_EEP_DEFINED_WORDS 10
1540#define ASC_EEP_MAX_ADDR 63
1541#define ASC_EEP_RES_WORDS 0
1542#define ASC_EEP_MAX_RETRY 20
1543#define ASC_MAX_INIT_BUSY_RETRY 8
1544#define ASC_EEP_ISA_PNP_WSIZE 16
1545
1546/*
1547 * These macros keep the chip SCSI id and ISA DMA speed
1548 * bitfields in board order. C bitfields aren't portable
1549 * between big and little-endian platforms so they are
1550 * not used.
1551 */
1552
1553#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f)
1554#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4)
1555#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
1556 ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
1557#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
1558 ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
1559
1560typedef struct asceep_config {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001561 ushort cfg_lsw;
1562 ushort cfg_msw;
1563 uchar init_sdtr;
1564 uchar disc_enable;
1565 uchar use_cmd_qng;
1566 uchar start_motor;
1567 uchar max_total_qng;
1568 uchar max_tag_qng;
1569 uchar bios_scan;
1570 uchar power_up_wait;
1571 uchar no_scam;
1572 uchar id_speed; /* low order 4 bits is chip scsi id */
1573 /* high order 4 bits is isa dma speed */
1574 uchar dos_int13_table[ASC_MAX_TID + 1];
1575 uchar adapter_info[6];
1576 ushort cntl;
1577 ushort chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578} ASCEEP_CONFIG;
1579
1580#define ASC_PCI_CFG_LSW_SCSI_PARITY 0x0800
1581#define ASC_PCI_CFG_LSW_BURST_MODE 0x0080
1582#define ASC_PCI_CFG_LSW_INTR_ABLE 0x0020
1583
1584#define ASC_EEP_CMD_READ 0x80
1585#define ASC_EEP_CMD_WRITE 0x40
1586#define ASC_EEP_CMD_WRITE_ABLE 0x30
1587#define ASC_EEP_CMD_WRITE_DISABLE 0x00
1588#define ASC_OVERRUN_BSIZE 0x00000048UL
1589#define ASC_CTRL_BREAK_ONCE 0x0001
1590#define ASC_CTRL_BREAK_STAY_IDLE 0x0002
1591#define ASCV_MSGOUT_BEG 0x0000
1592#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
1593#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
1594#define ASCV_BREAK_SAVED_CODE (ushort)0x0006
1595#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8)
1596#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3)
1597#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4)
1598#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8)
1599#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8)
1600#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020
1601#define ASCV_BREAK_ADDR (ushort)0x0028
1602#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A
1603#define ASCV_BREAK_CONTROL (ushort)0x002C
1604#define ASCV_BREAK_HIT_COUNT (ushort)0x002E
1605
1606#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030
1607#define ASCV_MCODE_CHKSUM_W (ushort)0x0032
1608#define ASCV_MCODE_SIZE_W (ushort)0x0034
1609#define ASCV_STOP_CODE_B (ushort)0x0036
1610#define ASCV_DVC_ERR_CODE_B (ushort)0x0037
1611#define ASCV_OVERRUN_PADDR_D (ushort)0x0038
1612#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C
1613#define ASCV_HALTCODE_W (ushort)0x0040
1614#define ASCV_CHKSUM_W (ushort)0x0042
1615#define ASCV_MC_DATE_W (ushort)0x0044
1616#define ASCV_MC_VER_W (ushort)0x0046
1617#define ASCV_NEXTRDY_B (ushort)0x0048
1618#define ASCV_DONENEXT_B (ushort)0x0049
1619#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
1620#define ASCV_SCSIBUSY_B (ushort)0x004B
1621#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C
1622#define ASCV_CURCDB_B (ushort)0x004D
1623#define ASCV_RCLUN_B (ushort)0x004E
1624#define ASCV_BUSY_QHEAD_B (ushort)0x004F
1625#define ASCV_DISC1_QHEAD_B (ushort)0x0050
1626#define ASCV_DISC_ENABLE_B (ushort)0x0052
1627#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
1628#define ASCV_HOSTSCSI_ID_B (ushort)0x0055
1629#define ASCV_MCODE_CNTL_B (ushort)0x0056
1630#define ASCV_NULL_TARGET_B (ushort)0x0057
1631#define ASCV_FREE_Q_HEAD_W (ushort)0x0058
1632#define ASCV_DONE_Q_TAIL_W (ushort)0x005A
1633#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1)
1634#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1)
1635#define ASCV_HOST_FLAG_B (ushort)0x005D
1636#define ASCV_TOTAL_READY_Q_B (ushort)0x0064
1637#define ASCV_VER_SERIAL_B (ushort)0x0065
1638#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
1639#define ASCV_WTM_FLAG_B (ushort)0x0068
1640#define ASCV_RISC_FLAG_B (ushort)0x006A
1641#define ASCV_REQ_SG_LIST_QP (ushort)0x006B
1642#define ASC_HOST_FLAG_IN_ISR 0x01
1643#define ASC_HOST_FLAG_ACK_INT 0x02
1644#define ASC_RISC_FLAG_GEN_INT 0x01
1645#define ASC_RISC_FLAG_REQ_SG_LIST 0x02
1646#define IOP_CTRL (0x0F)
1647#define IOP_STATUS (0x0E)
1648#define IOP_INT_ACK IOP_STATUS
1649#define IOP_REG_IFC (0x0D)
1650#define IOP_SYN_OFFSET (0x0B)
1651#define IOP_EXTRA_CONTROL (0x0D)
1652#define IOP_REG_PC (0x0C)
1653#define IOP_RAM_ADDR (0x0A)
1654#define IOP_RAM_DATA (0x08)
1655#define IOP_EEP_DATA (0x06)
1656#define IOP_EEP_CMD (0x07)
1657#define IOP_VERSION (0x03)
1658#define IOP_CONFIG_HIGH (0x04)
1659#define IOP_CONFIG_LOW (0x02)
1660#define IOP_SIG_BYTE (0x01)
1661#define IOP_SIG_WORD (0x00)
1662#define IOP_REG_DC1 (0x0E)
1663#define IOP_REG_DC0 (0x0C)
1664#define IOP_REG_SB (0x0B)
1665#define IOP_REG_DA1 (0x0A)
1666#define IOP_REG_DA0 (0x08)
1667#define IOP_REG_SC (0x09)
1668#define IOP_DMA_SPEED (0x07)
1669#define IOP_REG_FLAG (0x07)
1670#define IOP_FIFO_H (0x06)
1671#define IOP_FIFO_L (0x04)
1672#define IOP_REG_ID (0x05)
1673#define IOP_REG_QP (0x03)
1674#define IOP_REG_IH (0x02)
1675#define IOP_REG_IX (0x01)
1676#define IOP_REG_AX (0x00)
1677#define IFC_REG_LOCK (0x00)
1678#define IFC_REG_UNLOCK (0x09)
1679#define IFC_WR_EN_FILTER (0x10)
1680#define IFC_RD_NO_EEPROM (0x10)
1681#define IFC_SLEW_RATE (0x20)
1682#define IFC_ACT_NEG (0x40)
1683#define IFC_INP_FILTER (0x80)
1684#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK)
1685#define SC_SEL (uchar)(0x80)
1686#define SC_BSY (uchar)(0x40)
1687#define SC_ACK (uchar)(0x20)
1688#define SC_REQ (uchar)(0x10)
1689#define SC_ATN (uchar)(0x08)
1690#define SC_IO (uchar)(0x04)
1691#define SC_CD (uchar)(0x02)
1692#define SC_MSG (uchar)(0x01)
1693#define SEC_SCSI_CTL (uchar)(0x80)
1694#define SEC_ACTIVE_NEGATE (uchar)(0x40)
1695#define SEC_SLEW_RATE (uchar)(0x20)
1696#define SEC_ENABLE_FILTER (uchar)(0x10)
1697#define ASC_HALT_EXTMSG_IN (ushort)0x8000
1698#define ASC_HALT_CHK_CONDITION (ushort)0x8100
1699#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
1700#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300
1701#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400
1702#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
1703#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
1704#define ASC_MAX_QNO 0xF8
1705#define ASC_DATA_SEC_BEG (ushort)0x0080
1706#define ASC_DATA_SEC_END (ushort)0x0080
1707#define ASC_CODE_SEC_BEG (ushort)0x0080
1708#define ASC_CODE_SEC_END (ushort)0x0080
1709#define ASC_QADR_BEG (0x4000)
1710#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64)
1711#define ASC_QADR_END (ushort)0x7FFF
1712#define ASC_QLAST_ADR (ushort)0x7FC0
1713#define ASC_QBLK_SIZE 0x40
1714#define ASC_BIOS_DATA_QBEG 0xF8
1715#define ASC_MIN_ACTIVE_QNO 0x01
1716#define ASC_QLINK_END 0xFF
1717#define ASC_EEPROM_WORDS 0x10
1718#define ASC_MAX_MGS_LEN 0x10
1719#define ASC_BIOS_ADDR_DEF 0xDC00
1720#define ASC_BIOS_SIZE 0x3800
1721#define ASC_BIOS_RAM_OFF 0x3800
1722#define ASC_BIOS_RAM_SIZE 0x800
1723#define ASC_BIOS_MIN_ADDR 0xC000
1724#define ASC_BIOS_MAX_ADDR 0xEC00
1725#define ASC_BIOS_BANK_SIZE 0x0400
1726#define ASC_MCODE_START_ADDR 0x0080
1727#define ASC_CFG0_HOST_INT_ON 0x0020
1728#define ASC_CFG0_BIOS_ON 0x0040
1729#define ASC_CFG0_VERA_BURST_ON 0x0080
1730#define ASC_CFG0_SCSI_PARITY_ON 0x0800
1731#define ASC_CFG1_SCSI_TARGET_ON 0x0080
1732#define ASC_CFG1_LRAM_8BITS_ON 0x0800
1733#define ASC_CFG_MSW_CLR_MASK 0x3080
1734#define CSW_TEST1 (ASC_CS_TYPE)0x8000
1735#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
1736#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
1737#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000
1738#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800
1739#define CSW_TEST2 (ASC_CS_TYPE)0x0400
1740#define CSW_TEST3 (ASC_CS_TYPE)0x0200
1741#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100
1742#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080
1743#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040
1744#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020
1745#define CSW_HALTED (ASC_CS_TYPE)0x0010
1746#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
1747#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004
1748#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002
1749#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001
1750#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
1751#define CIW_INT_ACK (ASC_CS_TYPE)0x0100
1752#define CIW_TEST1 (ASC_CS_TYPE)0x0200
1753#define CIW_TEST2 (ASC_CS_TYPE)0x0400
1754#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800
1755#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000
1756#define CC_CHIP_RESET (uchar)0x80
1757#define CC_SCSI_RESET (uchar)0x40
1758#define CC_HALT (uchar)0x20
1759#define CC_SINGLE_STEP (uchar)0x10
1760#define CC_DMA_ABLE (uchar)0x08
1761#define CC_TEST (uchar)0x04
1762#define CC_BANK_ONE (uchar)0x02
1763#define CC_DIAG (uchar)0x01
1764#define ASC_1000_ID0W 0x04C1
1765#define ASC_1000_ID0W_FIX 0x00C1
1766#define ASC_1000_ID1B 0x25
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767#define ASC_EISA_REV_IOP_MASK (0x0C83)
1768#define ASC_EISA_PID_IOP_MASK (0x0C80)
1769#define ASC_EISA_CFG_IOP_MASK (0x0C86)
1770#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771#define INS_HALTINT (ushort)0x6281
1772#define INS_HALT (ushort)0x6280
1773#define INS_SINT (ushort)0x6200
1774#define INS_RFLAG_WTM (ushort)0x7380
1775#define ASC_MC_SAVE_CODE_WSIZE 0x500
1776#define ASC_MC_SAVE_DATA_WSIZE 0x40
1777
1778typedef struct asc_mc_saved {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001779 ushort data[ASC_MC_SAVE_DATA_WSIZE];
1780 ushort code[ASC_MC_SAVE_CODE_WSIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781} ASC_MC_SAVED;
1782
1783#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
1784#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
1785#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
1786#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
1787#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
1788#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
1789#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B)
1790#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B)
1791#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
1792#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val)
1793#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
1794#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
1795#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
1796#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
1797#define AscSynIndexToPeriod(index) (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
1798#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE)
1799#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD)
1800#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION)
1801#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW)
1802#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH)
1803#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data)
1804#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data)
1805#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD)
1806#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data)
1807#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA)
1808#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data)
1809#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
1810#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
1811#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA)
1812#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data)
1813#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC)
1814#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data)
1815#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
1816#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val)
1817#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL)
1818#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val)
1819#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET)
1820#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data)
1821#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data)
1822#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC)
1823#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
1824#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
1825#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL)
1826#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data)
1827#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX)
1828#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data)
1829#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX)
1830#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data)
1831#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH)
1832#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data)
1833#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP)
1834#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data)
1835#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L)
1836#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data)
1837#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H)
1838#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data)
1839#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED)
1840#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data)
1841#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0)
1842#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data)
1843#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1)
1844#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data)
1845#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0)
1846#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data)
1847#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1)
1848#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data)
1849#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID)
1850#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data)
1851
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001852static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
1853static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
1854static void AscWaitEEPRead(void);
1855static void AscWaitEEPWrite(void);
1856static ushort AscReadEEPWord(PortAddr, uchar);
1857static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
1858static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1859static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
1860static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
1861static int AscStartChip(PortAddr);
1862static int AscStopChip(PortAddr);
1863static void AscSetChipIH(PortAddr, ushort);
1864static int AscIsChipHalted(PortAddr);
1865static void AscAckInterrupt(PortAddr);
1866static void AscDisableInterrupt(PortAddr);
1867static void AscEnableInterrupt(PortAddr);
1868static void AscSetBank(PortAddr, uchar);
1869static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001871static ushort AscGetIsaDmaChannel(PortAddr);
1872static ushort AscSetIsaDmaChannel(PortAddr, ushort);
1873static uchar AscSetIsaDmaSpeed(PortAddr, uchar);
1874static uchar AscGetIsaDmaSpeed(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001876static uchar AscReadLramByte(PortAddr, ushort);
1877static ushort AscReadLramWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001879static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001881static void AscWriteLramWord(PortAddr, ushort, ushort);
1882static void AscWriteLramByte(PortAddr, ushort, uchar);
1883static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
1884static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
1885static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1886static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
1887static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
1888static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
1889static ushort AscInitFromEEP(ASC_DVC_VAR *);
1890static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
1891static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
1892static int AscTestExternalLram(ASC_DVC_VAR *);
1893static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
1894static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
1895static void AscSetChipSDTR(PortAddr, uchar, uchar);
1896static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
1897static uchar AscAllocFreeQueue(PortAddr, uchar);
1898static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
1899static int AscHostReqRiscHalt(PortAddr);
1900static int AscStopQueueExe(PortAddr);
1901static int AscSendScsiQueue(ASC_DVC_VAR *,
1902 ASC_SCSI_Q *scsiq, uchar n_q_required);
1903static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1904static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
1905static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
1906static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
1907static ushort AscInitLram(ASC_DVC_VAR *);
1908static ushort AscInitQLinkVar(ASC_DVC_VAR *);
1909static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
1910static int AscIsrChipHalted(ASC_DVC_VAR *);
1911static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
1912 ASC_QDONE_INFO *, ASC_DCNT);
1913static int AscIsrQDone(ASC_DVC_VAR *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001915static ushort AscGetEisaChipCfg(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001917static uchar AscGetChipScsiCtrl(PortAddr);
1918static uchar AscSetChipScsiID(PortAddr, uchar);
1919static uchar AscGetChipVersion(PortAddr, ushort);
1920static ushort AscGetChipBusType(PortAddr);
1921static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
1922static int AscFindSignature(PortAddr);
1923static void AscToggleIRQAct(PortAddr);
1924static uchar AscGetChipIRQ(PortAddr, ushort);
1925static uchar AscSetChipIRQ(PortAddr, uchar, ushort);
1926static ushort AscGetChipBiosAddress(PortAddr, ushort);
1927static inline ulong DvcEnterCritical(void);
1928static inline void DvcLeaveCritical(ulong);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001929static ushort AscGetChipBiosAddress(PortAddr, ushort);
1930static void DvcSleepMilliSecond(ASC_DCNT);
1931static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
1932static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1933static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001934static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
1935static void AscAsyncFix(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
1936static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
1937static void AscInquiryHandling(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
1938static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1939static int AscISR(ASC_DVC_VAR *);
1940static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1941static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001943static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001945static ASC_DCNT AscGetMaxDmaCount(ushort);
1946static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947
1948/*
1949 * --- Adv Library Constants and Macros
1950 */
1951
1952#define ADV_LIB_VERSION_MAJOR 5
1953#define ADV_LIB_VERSION_MINOR 14
1954
1955/*
1956 * Define Adv Library required special types.
1957 */
1958
1959/*
1960 * Portable Data Types
1961 *
1962 * Any instance where a 32-bit long or pointer type is assumed
1963 * for precision or HW defined structures, the following define
1964 * types must be used. In Linux the char, short, and int types
1965 * are all consistent at 8, 16, and 32 bits respectively. Pointers
1966 * and long types are 64 bits on Alpha and UltraSPARC.
1967 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001968#define ADV_PADDR __u32 /* Physical address data type. */
1969#define ADV_VADDR __u32 /* Virtual address data type. */
1970#define ADV_DCNT __u32 /* Unsigned Data count type. */
1971#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972
1973/*
1974 * These macros are used to convert a virtual address to a
1975 * 32-bit value. This currently can be used on Linux Alpha
1976 * which uses 64-bit virtual address but a 32-bit bus address.
1977 * This is likely to break in the future, but doing this now
1978 * will give us time to change the HW and FW to handle 64-bit
1979 * addresses.
1980 */
1981#define ADV_VADDR_TO_U32 virt_to_bus
1982#define ADV_U32_TO_VADDR bus_to_virt
1983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001984#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
1986/*
1987 * Define Adv Library required memory access macros.
1988 */
1989#define ADV_MEM_READB(addr) readb(addr)
1990#define ADV_MEM_READW(addr) readw(addr)
1991#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
1992#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
1993#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
1994
1995#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
1996
1997/*
1998 * For wide boards a CDB length maximum of 16 bytes
1999 * is supported.
2000 */
2001#define ADV_MAX_CDB_LEN 16
2002
2003/*
2004 * Define total number of simultaneous maximum element scatter-gather
2005 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
2006 * maximum number of outstanding commands per wide host adapter. Each
2007 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
2008 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
2009 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
2010 * structures or 255 scatter-gather elements.
2011 *
2012 */
2013#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
2014
2015/*
2016 * Define Adv Library required maximum number of scatter-gather
2017 * elements per request.
2018 */
2019#define ADV_MAX_SG_LIST 255
2020
2021/* Number of SG blocks needed. */
2022#define ADV_NUM_SG_BLOCK \
2023 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
2024
2025/* Total contiguous memory needed for SG blocks. */
2026#define ADV_SG_TOTAL_MEM_SIZE \
2027 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
2028
2029#define ADV_PAGE_SIZE PAGE_SIZE
2030
2031#define ADV_NUM_PAGE_CROSSING \
2032 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2033
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034#define ADV_EEP_DVC_CFG_BEGIN (0x00)
2035#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002036#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037#define ADV_EEP_MAX_WORD_ADDR (0x1E)
2038
2039#define ADV_EEP_DELAY_MS 100
2040
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002041#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
2042#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043/*
2044 * For the ASC3550 Bit 13 is Termination Polarity control bit.
2045 * For later ICs Bit 13 controls whether the CIS (Card Information
2046 * Service Section) is loaded from EEPROM.
2047 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002048#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
2049#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050/*
2051 * ASC38C1600 Bit 11
2052 *
2053 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
2054 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
2055 * Function 0 will specify INT B.
2056 *
2057 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
2058 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
2059 * Function 1 will specify INT A.
2060 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002061#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002063typedef struct adveep_3550_config {
2064 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002066 ushort cfg_lsw; /* 00 power up initialization */
2067 /* bit 13 set - Term Polarity Control */
2068 /* bit 14 set - BIOS Enable */
2069 /* bit 15 set - Big Endian Mode */
2070 ushort cfg_msw; /* 01 unused */
2071 ushort disc_enable; /* 02 disconnect enable */
2072 ushort wdtr_able; /* 03 Wide DTR able */
2073 ushort sdtr_able; /* 04 Synchronous DTR able */
2074 ushort start_motor; /* 05 send start up motor */
2075 ushort tagqng_able; /* 06 tag queuing able */
2076 ushort bios_scan; /* 07 BIOS device control */
2077 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002079 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2080 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002082 uchar scsi_reset_delay; /* 10 reset delay */
2083 uchar bios_id_lun; /* first boot device scsi id & lun */
2084 /* high nibble is lun */
2085 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002087 uchar termination; /* 11 0 - automatic */
2088 /* 1 - low off / high off */
2089 /* 2 - low off / high on */
2090 /* 3 - low on / high on */
2091 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002093 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002095 ushort bios_ctrl; /* 12 BIOS control bits */
2096 /* bit 0 BIOS don't act as initiator. */
2097 /* bit 1 BIOS > 1 GB support */
2098 /* bit 2 BIOS > 2 Disk Support */
2099 /* bit 3 BIOS don't support removables */
2100 /* bit 4 BIOS support bootable CD */
2101 /* bit 5 BIOS scan enabled */
2102 /* bit 6 BIOS support multiple LUNs */
2103 /* bit 7 BIOS display of message */
2104 /* bit 8 SCAM disabled */
2105 /* bit 9 Reset SCSI bus during init. */
2106 /* bit 10 */
2107 /* bit 11 No verbose initialization. */
2108 /* bit 12 SCSI parity enabled */
2109 /* bit 13 */
2110 /* bit 14 */
2111 /* bit 15 */
2112 ushort ultra_able; /* 13 ULTRA speed able */
2113 ushort reserved2; /* 14 reserved */
2114 uchar max_host_qng; /* 15 maximum host queuing */
2115 uchar max_dvc_qng; /* maximum per device queuing */
2116 ushort dvc_cntl; /* 16 control bit for driver */
2117 ushort bug_fix; /* 17 control bit for bug fix */
2118 ushort serial_number_word1; /* 18 Board serial number word 1 */
2119 ushort serial_number_word2; /* 19 Board serial number word 2 */
2120 ushort serial_number_word3; /* 20 Board serial number word 3 */
2121 ushort check_sum; /* 21 EEP check sum */
2122 uchar oem_name[16]; /* 22 OEM name */
2123 ushort dvc_err_code; /* 30 last device driver error code */
2124 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2125 ushort adv_err_addr; /* 32 last uc error address */
2126 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2127 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2128 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2129 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130} ADVEEP_3550_CONFIG;
2131
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002132typedef struct adveep_38C0800_config {
2133 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002135 ushort cfg_lsw; /* 00 power up initialization */
2136 /* bit 13 set - Load CIS */
2137 /* bit 14 set - BIOS Enable */
2138 /* bit 15 set - Big Endian Mode */
2139 ushort cfg_msw; /* 01 unused */
2140 ushort disc_enable; /* 02 disconnect enable */
2141 ushort wdtr_able; /* 03 Wide DTR able */
2142 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2143 ushort start_motor; /* 05 send start up motor */
2144 ushort tagqng_able; /* 06 tag queuing able */
2145 ushort bios_scan; /* 07 BIOS device control */
2146 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002148 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2149 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002151 uchar scsi_reset_delay; /* 10 reset delay */
2152 uchar bios_id_lun; /* first boot device scsi id & lun */
2153 /* high nibble is lun */
2154 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002156 uchar termination_se; /* 11 0 - automatic */
2157 /* 1 - low off / high off */
2158 /* 2 - low off / high on */
2159 /* 3 - low on / high on */
2160 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002162 uchar termination_lvd; /* 11 0 - automatic */
2163 /* 1 - low off / high off */
2164 /* 2 - low off / high on */
2165 /* 3 - low on / high on */
2166 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002168 ushort bios_ctrl; /* 12 BIOS control bits */
2169 /* bit 0 BIOS don't act as initiator. */
2170 /* bit 1 BIOS > 1 GB support */
2171 /* bit 2 BIOS > 2 Disk Support */
2172 /* bit 3 BIOS don't support removables */
2173 /* bit 4 BIOS support bootable CD */
2174 /* bit 5 BIOS scan enabled */
2175 /* bit 6 BIOS support multiple LUNs */
2176 /* bit 7 BIOS display of message */
2177 /* bit 8 SCAM disabled */
2178 /* bit 9 Reset SCSI bus during init. */
2179 /* bit 10 */
2180 /* bit 11 No verbose initialization. */
2181 /* bit 12 SCSI parity enabled */
2182 /* bit 13 */
2183 /* bit 14 */
2184 /* bit 15 */
2185 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2186 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2187 uchar max_host_qng; /* 15 maximum host queueing */
2188 uchar max_dvc_qng; /* maximum per device queuing */
2189 ushort dvc_cntl; /* 16 control bit for driver */
2190 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2191 ushort serial_number_word1; /* 18 Board serial number word 1 */
2192 ushort serial_number_word2; /* 19 Board serial number word 2 */
2193 ushort serial_number_word3; /* 20 Board serial number word 3 */
2194 ushort check_sum; /* 21 EEP check sum */
2195 uchar oem_name[16]; /* 22 OEM name */
2196 ushort dvc_err_code; /* 30 last device driver error code */
2197 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2198 ushort adv_err_addr; /* 32 last uc error address */
2199 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2200 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2201 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2202 ushort reserved36; /* 36 reserved */
2203 ushort reserved37; /* 37 reserved */
2204 ushort reserved38; /* 38 reserved */
2205 ushort reserved39; /* 39 reserved */
2206 ushort reserved40; /* 40 reserved */
2207 ushort reserved41; /* 41 reserved */
2208 ushort reserved42; /* 42 reserved */
2209 ushort reserved43; /* 43 reserved */
2210 ushort reserved44; /* 44 reserved */
2211 ushort reserved45; /* 45 reserved */
2212 ushort reserved46; /* 46 reserved */
2213 ushort reserved47; /* 47 reserved */
2214 ushort reserved48; /* 48 reserved */
2215 ushort reserved49; /* 49 reserved */
2216 ushort reserved50; /* 50 reserved */
2217 ushort reserved51; /* 51 reserved */
2218 ushort reserved52; /* 52 reserved */
2219 ushort reserved53; /* 53 reserved */
2220 ushort reserved54; /* 54 reserved */
2221 ushort reserved55; /* 55 reserved */
2222 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2223 ushort cisprt_msw; /* 57 CIS PTR MSW */
2224 ushort subsysvid; /* 58 SubSystem Vendor ID */
2225 ushort subsysid; /* 59 SubSystem ID */
2226 ushort reserved60; /* 60 reserved */
2227 ushort reserved61; /* 61 reserved */
2228 ushort reserved62; /* 62 reserved */
2229 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230} ADVEEP_38C0800_CONFIG;
2231
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002232typedef struct adveep_38C1600_config {
2233 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002235 ushort cfg_lsw; /* 00 power up initialization */
2236 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
2237 /* clear - Func. 0 INTA, Func. 1 INTB */
2238 /* bit 13 set - Load CIS */
2239 /* bit 14 set - BIOS Enable */
2240 /* bit 15 set - Big Endian Mode */
2241 ushort cfg_msw; /* 01 unused */
2242 ushort disc_enable; /* 02 disconnect enable */
2243 ushort wdtr_able; /* 03 Wide DTR able */
2244 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2245 ushort start_motor; /* 05 send start up motor */
2246 ushort tagqng_able; /* 06 tag queuing able */
2247 ushort bios_scan; /* 07 BIOS device control */
2248 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002250 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2251 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002253 uchar scsi_reset_delay; /* 10 reset delay */
2254 uchar bios_id_lun; /* first boot device scsi id & lun */
2255 /* high nibble is lun */
2256 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002258 uchar termination_se; /* 11 0 - automatic */
2259 /* 1 - low off / high off */
2260 /* 2 - low off / high on */
2261 /* 3 - low on / high on */
2262 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002264 uchar termination_lvd; /* 11 0 - automatic */
2265 /* 1 - low off / high off */
2266 /* 2 - low off / high on */
2267 /* 3 - low on / high on */
2268 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002270 ushort bios_ctrl; /* 12 BIOS control bits */
2271 /* bit 0 BIOS don't act as initiator. */
2272 /* bit 1 BIOS > 1 GB support */
2273 /* bit 2 BIOS > 2 Disk Support */
2274 /* bit 3 BIOS don't support removables */
2275 /* bit 4 BIOS support bootable CD */
2276 /* bit 5 BIOS scan enabled */
2277 /* bit 6 BIOS support multiple LUNs */
2278 /* bit 7 BIOS display of message */
2279 /* bit 8 SCAM disabled */
2280 /* bit 9 Reset SCSI bus during init. */
2281 /* bit 10 Basic Integrity Checking disabled */
2282 /* bit 11 No verbose initialization. */
2283 /* bit 12 SCSI parity enabled */
2284 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
2285 /* bit 14 */
2286 /* bit 15 */
2287 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2288 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2289 uchar max_host_qng; /* 15 maximum host queueing */
2290 uchar max_dvc_qng; /* maximum per device queuing */
2291 ushort dvc_cntl; /* 16 control bit for driver */
2292 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2293 ushort serial_number_word1; /* 18 Board serial number word 1 */
2294 ushort serial_number_word2; /* 19 Board serial number word 2 */
2295 ushort serial_number_word3; /* 20 Board serial number word 3 */
2296 ushort check_sum; /* 21 EEP check sum */
2297 uchar oem_name[16]; /* 22 OEM name */
2298 ushort dvc_err_code; /* 30 last device driver error code */
2299 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2300 ushort adv_err_addr; /* 32 last uc error address */
2301 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2302 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2303 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2304 ushort reserved36; /* 36 reserved */
2305 ushort reserved37; /* 37 reserved */
2306 ushort reserved38; /* 38 reserved */
2307 ushort reserved39; /* 39 reserved */
2308 ushort reserved40; /* 40 reserved */
2309 ushort reserved41; /* 41 reserved */
2310 ushort reserved42; /* 42 reserved */
2311 ushort reserved43; /* 43 reserved */
2312 ushort reserved44; /* 44 reserved */
2313 ushort reserved45; /* 45 reserved */
2314 ushort reserved46; /* 46 reserved */
2315 ushort reserved47; /* 47 reserved */
2316 ushort reserved48; /* 48 reserved */
2317 ushort reserved49; /* 49 reserved */
2318 ushort reserved50; /* 50 reserved */
2319 ushort reserved51; /* 51 reserved */
2320 ushort reserved52; /* 52 reserved */
2321 ushort reserved53; /* 53 reserved */
2322 ushort reserved54; /* 54 reserved */
2323 ushort reserved55; /* 55 reserved */
2324 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2325 ushort cisprt_msw; /* 57 CIS PTR MSW */
2326 ushort subsysvid; /* 58 SubSystem Vendor ID */
2327 ushort subsysid; /* 59 SubSystem ID */
2328 ushort reserved60; /* 60 reserved */
2329 ushort reserved61; /* 61 reserved */
2330 ushort reserved62; /* 62 reserved */
2331 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332} ADVEEP_38C1600_CONFIG;
2333
2334/*
2335 * EEPROM Commands
2336 */
2337#define ASC_EEP_CMD_DONE 0x0200
2338#define ASC_EEP_CMD_DONE_ERR 0x0001
2339
2340/* cfg_word */
2341#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
2342
2343/* bios_ctrl */
2344#define BIOS_CTRL_BIOS 0x0001
2345#define BIOS_CTRL_EXTENDED_XLAT 0x0002
2346#define BIOS_CTRL_GT_2_DISK 0x0004
2347#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
2348#define BIOS_CTRL_BOOTABLE_CD 0x0010
2349#define BIOS_CTRL_MULTIPLE_LUN 0x0040
2350#define BIOS_CTRL_DISPLAY_MSG 0x0080
2351#define BIOS_CTRL_NO_SCAM 0x0100
2352#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
2353#define BIOS_CTRL_INIT_VERBOSE 0x0800
2354#define BIOS_CTRL_SCSI_PARITY 0x1000
2355#define BIOS_CTRL_AIPP_DIS 0x2000
2356
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002357#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
2358#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002360#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2361#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362
2363/*
2364 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
2365 * a special 16K Adv Library and Microcode version. After the issue is
2366 * resolved, should restore 32K support.
2367 *
2368 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
2369 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002370#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2371#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
2372#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
2374/*
2375 * Byte I/O register address from base of 'iop_base'.
2376 */
2377#define IOPB_INTR_STATUS_REG 0x00
2378#define IOPB_CHIP_ID_1 0x01
2379#define IOPB_INTR_ENABLES 0x02
2380#define IOPB_CHIP_TYPE_REV 0x03
2381#define IOPB_RES_ADDR_4 0x04
2382#define IOPB_RES_ADDR_5 0x05
2383#define IOPB_RAM_DATA 0x06
2384#define IOPB_RES_ADDR_7 0x07
2385#define IOPB_FLAG_REG 0x08
2386#define IOPB_RES_ADDR_9 0x09
2387#define IOPB_RISC_CSR 0x0A
2388#define IOPB_RES_ADDR_B 0x0B
2389#define IOPB_RES_ADDR_C 0x0C
2390#define IOPB_RES_ADDR_D 0x0D
2391#define IOPB_SOFT_OVER_WR 0x0E
2392#define IOPB_RES_ADDR_F 0x0F
2393#define IOPB_MEM_CFG 0x10
2394#define IOPB_RES_ADDR_11 0x11
2395#define IOPB_GPIO_DATA 0x12
2396#define IOPB_RES_ADDR_13 0x13
2397#define IOPB_FLASH_PAGE 0x14
2398#define IOPB_RES_ADDR_15 0x15
2399#define IOPB_GPIO_CNTL 0x16
2400#define IOPB_RES_ADDR_17 0x17
2401#define IOPB_FLASH_DATA 0x18
2402#define IOPB_RES_ADDR_19 0x19
2403#define IOPB_RES_ADDR_1A 0x1A
2404#define IOPB_RES_ADDR_1B 0x1B
2405#define IOPB_RES_ADDR_1C 0x1C
2406#define IOPB_RES_ADDR_1D 0x1D
2407#define IOPB_RES_ADDR_1E 0x1E
2408#define IOPB_RES_ADDR_1F 0x1F
2409#define IOPB_DMA_CFG0 0x20
2410#define IOPB_DMA_CFG1 0x21
2411#define IOPB_TICKLE 0x22
2412#define IOPB_DMA_REG_WR 0x23
2413#define IOPB_SDMA_STATUS 0x24
2414#define IOPB_SCSI_BYTE_CNT 0x25
2415#define IOPB_HOST_BYTE_CNT 0x26
2416#define IOPB_BYTE_LEFT_TO_XFER 0x27
2417#define IOPB_BYTE_TO_XFER_0 0x28
2418#define IOPB_BYTE_TO_XFER_1 0x29
2419#define IOPB_BYTE_TO_XFER_2 0x2A
2420#define IOPB_BYTE_TO_XFER_3 0x2B
2421#define IOPB_ACC_GRP 0x2C
2422#define IOPB_RES_ADDR_2D 0x2D
2423#define IOPB_DEV_ID 0x2E
2424#define IOPB_RES_ADDR_2F 0x2F
2425#define IOPB_SCSI_DATA 0x30
2426#define IOPB_RES_ADDR_31 0x31
2427#define IOPB_RES_ADDR_32 0x32
2428#define IOPB_SCSI_DATA_HSHK 0x33
2429#define IOPB_SCSI_CTRL 0x34
2430#define IOPB_RES_ADDR_35 0x35
2431#define IOPB_RES_ADDR_36 0x36
2432#define IOPB_RES_ADDR_37 0x37
2433#define IOPB_RAM_BIST 0x38
2434#define IOPB_PLL_TEST 0x39
2435#define IOPB_PCI_INT_CFG 0x3A
2436#define IOPB_RES_ADDR_3B 0x3B
2437#define IOPB_RFIFO_CNT 0x3C
2438#define IOPB_RES_ADDR_3D 0x3D
2439#define IOPB_RES_ADDR_3E 0x3E
2440#define IOPB_RES_ADDR_3F 0x3F
2441
2442/*
2443 * Word I/O register address from base of 'iop_base'.
2444 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002445#define IOPW_CHIP_ID_0 0x00 /* CID0 */
2446#define IOPW_CTRL_REG 0x02 /* CC */
2447#define IOPW_RAM_ADDR 0x04 /* LA */
2448#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002450#define IOPW_RISC_CSR 0x0A /* CSR */
2451#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
2452#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002454#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002456#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002458#define IOPW_EE_CMD 0x1A /* EC */
2459#define IOPW_EE_DATA 0x1C /* ED */
2460#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002462#define IOPW_Q_BASE 0x22 /* QB */
2463#define IOPW_QP 0x24 /* QP */
2464#define IOPW_IX 0x26 /* IX */
2465#define IOPW_SP 0x28 /* SP */
2466#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467#define IOPW_RES_ADDR_2C 0x2C
2468#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002469#define IOPW_SCSI_DATA 0x30 /* SD */
2470#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
2471#define IOPW_SCSI_CTRL 0x34 /* SC */
2472#define IOPW_HSHK_CFG 0x36 /* HCFG */
2473#define IOPW_SXFR_STATUS 0x36 /* SXS */
2474#define IOPW_SXFR_CNTL 0x38 /* SXL */
2475#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002477#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
2479/*
2480 * Doubleword I/O register address from base of 'iop_base'.
2481 */
2482#define IOPDW_RES_ADDR_0 0x00
2483#define IOPDW_RAM_DATA 0x04
2484#define IOPDW_RES_ADDR_8 0x08
2485#define IOPDW_RES_ADDR_C 0x0C
2486#define IOPDW_RES_ADDR_10 0x10
2487#define IOPDW_COMMA 0x14
2488#define IOPDW_COMMB 0x18
2489#define IOPDW_RES_ADDR_1C 0x1C
2490#define IOPDW_SDMA_ADDR0 0x20
2491#define IOPDW_SDMA_ADDR1 0x24
2492#define IOPDW_SDMA_COUNT 0x28
2493#define IOPDW_SDMA_ERROR 0x2C
2494#define IOPDW_RDMA_ADDR0 0x30
2495#define IOPDW_RDMA_ADDR1 0x34
2496#define IOPDW_RDMA_COUNT 0x38
2497#define IOPDW_RDMA_ERROR 0x3C
2498
2499#define ADV_CHIP_ID_BYTE 0x25
2500#define ADV_CHIP_ID_WORD 0x04C1
2501
2502#define ADV_SC_SCSI_BUS_RESET 0x2000
2503
2504#define ADV_INTR_ENABLE_HOST_INTR 0x01
2505#define ADV_INTR_ENABLE_SEL_INTR 0x02
2506#define ADV_INTR_ENABLE_DPR_INTR 0x04
2507#define ADV_INTR_ENABLE_RTA_INTR 0x08
2508#define ADV_INTR_ENABLE_RMA_INTR 0x10
2509#define ADV_INTR_ENABLE_RST_INTR 0x20
2510#define ADV_INTR_ENABLE_DPE_INTR 0x40
2511#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
2512
2513#define ADV_INTR_STATUS_INTRA 0x01
2514#define ADV_INTR_STATUS_INTRB 0x02
2515#define ADV_INTR_STATUS_INTRC 0x04
2516
2517#define ADV_RISC_CSR_STOP (0x0000)
2518#define ADV_RISC_TEST_COND (0x2000)
2519#define ADV_RISC_CSR_RUN (0x4000)
2520#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
2521
2522#define ADV_CTRL_REG_HOST_INTR 0x0100
2523#define ADV_CTRL_REG_SEL_INTR 0x0200
2524#define ADV_CTRL_REG_DPR_INTR 0x0400
2525#define ADV_CTRL_REG_RTA_INTR 0x0800
2526#define ADV_CTRL_REG_RMA_INTR 0x1000
2527#define ADV_CTRL_REG_RES_BIT14 0x2000
2528#define ADV_CTRL_REG_DPE_INTR 0x4000
2529#define ADV_CTRL_REG_POWER_DONE 0x8000
2530#define ADV_CTRL_REG_ANY_INTR 0xFF00
2531
2532#define ADV_CTRL_REG_CMD_RESET 0x00C6
2533#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
2534#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
2535#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
2536#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
2537
2538#define ADV_TICKLE_NOP 0x00
2539#define ADV_TICKLE_A 0x01
2540#define ADV_TICKLE_B 0x02
2541#define ADV_TICKLE_C 0x03
2542
2543#define ADV_SCSI_CTRL_RSTOUT 0x2000
2544
2545#define AdvIsIntPending(port) \
2546 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
2547
2548/*
2549 * SCSI_CFG0 Register bit definitions
2550 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002551#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
2552#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
2553#define EVEN_PARITY 0x1000 /* Select Even Parity */
2554#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
2555#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
2556#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
2557#define SCAM_EN 0x0080 /* Enable SCAM selection */
2558#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
2559#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
2560#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
2561#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562
2563/*
2564 * SCSI_CFG1 Register bit definitions
2565 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002566#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
2567#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
2568#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
2569#define FILTER_SEL 0x0C00 /* Filter Period Selection */
2570#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
2571#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
2572#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
2573#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
2574#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
2575#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
2576#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
2577#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
2578#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
2579#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
2580#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581
2582/*
2583 * Addendum for ASC-38C0800 Chip
2584 *
2585 * The ASC-38C1600 Chip uses the same definitions except that the
2586 * bus mode override bits [12:10] have been moved to byte register
2587 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
2588 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
2589 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
2590 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
2591 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
2592 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002593#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
2594#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
2595#define HVD 0x1000 /* HVD Device Detect */
2596#define LVD 0x0800 /* LVD Device Detect */
2597#define SE 0x0400 /* SE Device Detect */
2598#define TERM_LVD 0x00C0 /* LVD Termination Bits */
2599#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
2600#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
2601#define TERM_SE 0x0030 /* SE Termination Bits */
2602#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
2603#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
2604#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
2605#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
2606#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
2607#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
2608#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
2609#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
2611#define CABLE_ILLEGAL_A 0x7
2612 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
2613
2614#define CABLE_ILLEGAL_B 0xB
2615 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
2616
2617/*
2618 * MEM_CFG Register bit definitions
2619 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002620#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
2621#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
2622#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
2623#define RAM_SZ_2KB 0x00 /* 2 KB */
2624#define RAM_SZ_4KB 0x04 /* 4 KB */
2625#define RAM_SZ_8KB 0x08 /* 8 KB */
2626#define RAM_SZ_16KB 0x0C /* 16 KB */
2627#define RAM_SZ_32KB 0x10 /* 32 KB */
2628#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629
2630/*
2631 * DMA_CFG0 Register bit definitions
2632 *
2633 * This register is only accessible to the host.
2634 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002635#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
2636#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
2637#define FIFO_THRESH_16B 0x00 /* 16 bytes */
2638#define FIFO_THRESH_32B 0x20 /* 32 bytes */
2639#define FIFO_THRESH_48B 0x30 /* 48 bytes */
2640#define FIFO_THRESH_64B 0x40 /* 64 bytes */
2641#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
2642#define FIFO_THRESH_96B 0x60 /* 96 bytes */
2643#define FIFO_THRESH_112B 0x70 /* 112 bytes */
2644#define START_CTL 0x0C /* DMA start conditions */
2645#define START_CTL_TH 0x00 /* Wait threshold level (default) */
2646#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
2647#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
2648#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
2649#define READ_CMD 0x03 /* Memory Read Method */
2650#define READ_CMD_MR 0x00 /* Memory Read */
2651#define READ_CMD_MRL 0x02 /* Memory Read Long */
2652#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653
2654/*
2655 * ASC-38C0800 RAM BIST Register bit definitions
2656 */
2657#define RAM_TEST_MODE 0x80
2658#define PRE_TEST_MODE 0x40
2659#define NORMAL_MODE 0x00
2660#define RAM_TEST_DONE 0x10
2661#define RAM_TEST_STATUS 0x0F
2662#define RAM_TEST_HOST_ERROR 0x08
2663#define RAM_TEST_INTRAM_ERROR 0x04
2664#define RAM_TEST_RISC_ERROR 0x02
2665#define RAM_TEST_SCSI_ERROR 0x01
2666#define RAM_TEST_SUCCESS 0x00
2667#define PRE_TEST_VALUE 0x05
2668#define NORMAL_VALUE 0x00
2669
2670/*
2671 * ASC38C1600 Definitions
2672 *
2673 * IOPB_PCI_INT_CFG Bit Field Definitions
2674 */
2675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002676#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677
2678/*
2679 * Bit 1 can be set to change the interrupt for the Function to operate in
2680 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
2681 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
2682 * mode, otherwise the operating mode is undefined.
2683 */
2684#define TOTEMPOLE 0x02
2685
2686/*
2687 * Bit 0 can be used to change the Int Pin for the Function. The value is
2688 * 0 by default for both Functions with Function 0 using INT A and Function
2689 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
2690 * INT A is used.
2691 *
2692 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
2693 * value specified in the PCI Configuration Space.
2694 */
2695#define INTAB 0x01
2696
2697/* a_advlib.h */
2698
2699/*
2700 * Adv Library Status Definitions
2701 */
2702#define ADV_TRUE 1
2703#define ADV_FALSE 0
2704#define ADV_NOERROR 1
2705#define ADV_SUCCESS 1
2706#define ADV_BUSY 0
2707#define ADV_ERROR (-1)
2708
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709/*
2710 * ADV_DVC_VAR 'warn_code' values
2711 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002712#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
2713#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
2714#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
2715#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
2716#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002718#define ADV_MAX_TID 15 /* max. target identifier */
2719#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720
2721/*
2722 * Error code values are set in ADV_DVC_VAR 'err_code'.
2723 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002724#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
2725#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
2726#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
2727#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
2728#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
2729#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
2730#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
2731#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
2732#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
2733#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
2734#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
2735#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
2736#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
2737#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738
2739/*
2740 * Fixed locations of microcode operating variables.
2741 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002742#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
2743#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
2744#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
2745#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
2746#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
2747#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
2748#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
2749#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
2750#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
2751#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
2752#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
2753#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
2754#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755#define ASC_MC_CHIP_TYPE 0x009A
2756#define ASC_MC_INTRB_CODE 0x009B
2757#define ASC_MC_WDTR_ABLE 0x009C
2758#define ASC_MC_SDTR_ABLE 0x009E
2759#define ASC_MC_TAGQNG_ABLE 0x00A0
2760#define ASC_MC_DISC_ENABLE 0x00A2
2761#define ASC_MC_IDLE_CMD_STATUS 0x00A4
2762#define ASC_MC_IDLE_CMD 0x00A6
2763#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
2764#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
2765#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
2766#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
2767#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
2768#define ASC_MC_SDTR_DONE 0x00B6
2769#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
2770#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
2771#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002772#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002774#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775#define ASC_MC_ICQ 0x0160
2776#define ASC_MC_IRQ 0x0164
2777#define ASC_MC_PPR_ABLE 0x017A
2778
2779/*
2780 * BIOS LRAM variable absolute offsets.
2781 */
2782#define BIOS_CODESEG 0x54
2783#define BIOS_CODELEN 0x56
2784#define BIOS_SIGNATURE 0x58
2785#define BIOS_VERSION 0x5A
2786
2787/*
2788 * Microcode Control Flags
2789 *
2790 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
2791 * and handled by the microcode.
2792 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002793#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
2794#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795
2796/*
2797 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
2798 */
2799#define HSHK_CFG_WIDE_XFR 0x8000
2800#define HSHK_CFG_RATE 0x0F00
2801#define HSHK_CFG_OFFSET 0x001F
2802
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002803#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
2804#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
2805#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
2806#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002808#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2809#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2810#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2811#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2812#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002814#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2815#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2816#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2817#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2818#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819/*
2820 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2821 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2822 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002823#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2824#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825
2826/*
2827 * All fields here are accessed by the board microcode and need to be
2828 * little-endian.
2829 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002830typedef struct adv_carr_t {
2831 ADV_VADDR carr_va; /* Carrier Virtual Address */
2832 ADV_PADDR carr_pa; /* Carrier Physical Address */
2833 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2834 /*
2835 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2836 *
2837 * next_vpa [3:1] Reserved Bits
2838 * next_vpa [0] Done Flag set in Response Queue.
2839 */
2840 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841} ADV_CARR_T;
2842
2843/*
2844 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2845 */
2846#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2847
2848#define ASC_RQ_DONE 0x00000001
2849#define ASC_RQ_GOOD 0x00000002
2850#define ASC_CQ_STOPPER 0x00000000
2851
2852#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2853
2854#define ADV_CARRIER_NUM_PAGE_CROSSING \
2855 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2856 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2857
2858#define ADV_CARRIER_BUFSIZE \
2859 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2860
2861/*
2862 * ASC_SCSI_REQ_Q 'a_flag' definitions
2863 *
2864 * The Adv Library should limit use to the lower nibble (4 bits) of
2865 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2866 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002867#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2868#define ADV_SCSIQ_DONE 0x02 /* request done */
2869#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002871#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2872#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2873#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874
2875/*
2876 * Adapter temporary configuration structure
2877 *
2878 * This structure can be discarded after initialization. Don't add
2879 * fields here needed after initialization.
2880 *
2881 * Field naming convention:
2882 *
2883 * *_enable indicates the field enables or disables a feature. The
2884 * value of the field is never reset.
2885 */
2886typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002887 ushort disc_enable; /* enable disconnection */
2888 uchar chip_version; /* chip version */
2889 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2890 ushort lib_version; /* Adv Library version number */
2891 ushort control_flag; /* Microcode Control Flag */
2892 ushort mcode_date; /* Microcode date */
2893 ushort mcode_version; /* Microcode version */
2894 ushort pci_slot_info; /* high byte device/function number */
2895 /* bits 7-3 device num., bits 2-0 function num. */
2896 /* low byte bus num. */
2897 ushort serial1; /* EEPROM serial number word 1 */
2898 ushort serial2; /* EEPROM serial number word 2 */
2899 ushort serial3; /* EEPROM serial number word 3 */
2900 struct device *dev; /* pointer to the pci dev structure for this board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901} ADV_DVC_CFG;
2902
2903struct adv_dvc_var;
2904struct adv_scsi_req_q;
2905
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002906typedef void (*ADV_ISR_CALLBACK)
2907 (struct adv_dvc_var *, struct adv_scsi_req_q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002909typedef void (*ADV_ASYNC_CALLBACK)
2910 (struct adv_dvc_var *, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911
2912/*
2913 * Adapter operation variable structure.
2914 *
2915 * One structure is required per host adapter.
2916 *
2917 * Field naming convention:
2918 *
2919 * *_able indicates both whether a feature should be enabled or disabled
2920 * and whether a device isi capable of the feature. At initialization
2921 * this field may be set, but later if a device is found to be incapable
2922 * of the feature, the field is cleared.
2923 */
2924typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002925 AdvPortAddr iop_base; /* I/O port address */
2926 ushort err_code; /* fatal error code */
2927 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
2928 ADV_ISR_CALLBACK isr_callback;
2929 ADV_ASYNC_CALLBACK async_callback;
2930 ushort wdtr_able; /* try WDTR for a device */
2931 ushort sdtr_able; /* try SDTR for a device */
2932 ushort ultra_able; /* try SDTR Ultra speed for a device */
2933 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2934 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2935 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2936 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2937 ushort tagqng_able; /* try tagged queuing with a device */
2938 ushort ppr_able; /* PPR message capable per TID bitmask. */
2939 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2940 ushort start_motor; /* start motor command allowed */
2941 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2942 uchar chip_no; /* should be assigned by caller */
2943 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2944 uchar irq_no; /* IRQ number */
2945 ushort no_scam; /* scam_tolerant of EEPROM */
2946 struct asc_board *drv_ptr; /* driver pointer to private structure */
2947 uchar chip_scsi_id; /* chip SCSI target ID */
2948 uchar chip_type;
2949 uchar bist_err_code;
2950 ADV_CARR_T *carrier_buf;
2951 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2952 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2953 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2954 ushort carr_pending_cnt; /* Count of pending carriers. */
2955 /*
2956 * Note: The following fields will not be used after initialization. The
2957 * driver may discard the buffer after initialization is done.
2958 */
2959 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960} ADV_DVC_VAR;
2961
2962#define NO_OF_SG_PER_BLOCK 15
2963
2964typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002965 uchar reserved1;
2966 uchar reserved2;
2967 uchar reserved3;
2968 uchar sg_cnt; /* Valid entries in block. */
2969 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
2970 struct {
2971 ADV_PADDR sg_addr; /* SG element address. */
2972 ADV_DCNT sg_count; /* SG element count. */
2973 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974} ADV_SG_BLOCK;
2975
2976/*
2977 * ADV_SCSI_REQ_Q - microcode request structure
2978 *
2979 * All fields in this structure up to byte 60 are used by the microcode.
2980 * The microcode makes assumptions about the size and ordering of fields
2981 * in this structure. Do not change the structure definition here without
2982 * coordinating the change with the microcode.
2983 *
2984 * All fields accessed by microcode must be maintained in little_endian
2985 * order.
2986 */
2987typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002988 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
2989 uchar target_cmd;
2990 uchar target_id; /* Device target identifier. */
2991 uchar target_lun; /* Device target logical unit number. */
2992 ADV_PADDR data_addr; /* Data buffer physical address. */
2993 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
2994 ADV_PADDR sense_addr;
2995 ADV_PADDR carr_pa;
2996 uchar mflag;
2997 uchar sense_len;
2998 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
2999 uchar scsi_cntl;
3000 uchar done_status; /* Completion status. */
3001 uchar scsi_status; /* SCSI status byte. */
3002 uchar host_status; /* Ucode host status. */
3003 uchar sg_working_ix;
3004 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
3005 ADV_PADDR sg_real_addr; /* SG list physical address. */
3006 ADV_PADDR scsiq_rptr;
3007 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
3008 ADV_VADDR scsiq_ptr;
3009 ADV_VADDR carr_va;
3010 /*
3011 * End of microcode structure - 60 bytes. The rest of the structure
3012 * is used by the Adv Library and ignored by the microcode.
3013 */
3014 ADV_VADDR srb_ptr;
3015 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
3016 char *vdata_addr; /* Data buffer virtual address. */
3017 uchar a_flag;
3018 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019} ADV_SCSI_REQ_Q;
3020
3021/*
3022 * Microcode idle loop commands
3023 */
3024#define IDLE_CMD_COMPLETED 0
3025#define IDLE_CMD_STOP_CHIP 0x0001
3026#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
3027#define IDLE_CMD_SEND_INT 0x0004
3028#define IDLE_CMD_ABORT 0x0008
3029#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003030#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
3031#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032#define IDLE_CMD_SCSIREQ 0x0080
3033
3034#define IDLE_CMD_STATUS_SUCCESS 0x0001
3035#define IDLE_CMD_STATUS_FAILURE 0x0002
3036
3037/*
3038 * AdvSendIdleCmd() flag definitions.
3039 */
3040#define ADV_NOWAIT 0x01
3041
3042/*
3043 * Wait loop time out values.
3044 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003045#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
3046#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
3047#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
3048#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
3049#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003051#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
3052#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
3053#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
3054#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003056#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057
3058/*
3059 * Device drivers must define the following functions.
3060 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003061static inline ulong DvcEnterCritical(void);
3062static inline void DvcLeaveCritical(ulong);
3063static void DvcSleepMilliSecond(ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003064static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
3065 uchar *, ASC_SDCNT *, int);
3066static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067
3068/*
3069 * Adv Library functions available to drivers.
3070 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003071static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3072static int AdvISR(ADV_DVC_VAR *);
3073static int AdvInitGetConfig(ADV_DVC_VAR *);
3074static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
3075static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
3076static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
3077static int AdvResetChipAndSB(ADV_DVC_VAR *);
3078static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079
3080/*
3081 * Internal Adv Library functions.
3082 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003083static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
3084static void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3085static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
3086static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
3087static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
3088static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3089static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3090static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3091static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3092static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3093static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3094static void AdvWaitEEPCmd(AdvPortAddr);
3095static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097/* Read byte from a register. */
3098#define AdvReadByteRegister(iop_base, reg_off) \
3099 (ADV_MEM_READB((iop_base) + (reg_off)))
3100
3101/* Write byte to a register. */
3102#define AdvWriteByteRegister(iop_base, reg_off, byte) \
3103 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
3104
3105/* Read word (2 bytes) from a register. */
3106#define AdvReadWordRegister(iop_base, reg_off) \
3107 (ADV_MEM_READW((iop_base) + (reg_off)))
3108
3109/* Write word (2 bytes) to a register. */
3110#define AdvWriteWordRegister(iop_base, reg_off, word) \
3111 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
3112
3113/* Write dword (4 bytes) to a register. */
3114#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
3115 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
3116
3117/* Read byte from LRAM. */
3118#define AdvReadByteLram(iop_base, addr, byte) \
3119do { \
3120 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3121 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
3122} while (0)
3123
3124/* Write byte to LRAM. */
3125#define AdvWriteByteLram(iop_base, addr, byte) \
3126 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3127 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
3128
3129/* Read word (2 bytes) from LRAM. */
3130#define AdvReadWordLram(iop_base, addr, word) \
3131do { \
3132 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3133 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
3134} while (0)
3135
3136/* Write word (2 bytes) to LRAM. */
3137#define AdvWriteWordLram(iop_base, addr, word) \
3138 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3139 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3140
3141/* Write little-endian double word (4 bytes) to LRAM */
3142/* Because of unspecified C language ordering don't use auto-increment. */
3143#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
3144 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3145 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3146 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
3147 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
3148 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3149 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
3150
3151/* Read word (2 bytes) from LRAM assuming that the address is already set. */
3152#define AdvReadWordAutoIncLram(iop_base) \
3153 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
3154
3155/* Write word (2 bytes) to LRAM assuming that the address is already set. */
3156#define AdvWriteWordAutoIncLram(iop_base, word) \
3157 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3158
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159/*
3160 * Define macro to check for Condor signature.
3161 *
3162 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
3163 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
3164 */
3165#define AdvFindSignature(iop_base) \
3166 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
3167 ADV_CHIP_ID_BYTE) && \
3168 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
3169 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
3170
3171/*
3172 * Define macro to Return the version number of the chip at 'iop_base'.
3173 *
3174 * The second parameter 'bus_type' is currently unused.
3175 */
3176#define AdvGetChipVersion(iop_base, bus_type) \
3177 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
3178
3179/*
3180 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
3181 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
3182 *
3183 * If the request has not yet been sent to the device it will simply be
3184 * aborted from RISC memory. If the request is disconnected it will be
3185 * aborted on reselection by sending an Abort Message to the target ID.
3186 *
3187 * Return value:
3188 * ADV_TRUE(1) - Queue was successfully aborted.
3189 * ADV_FALSE(0) - Queue was not found on the active queue list.
3190 */
3191#define AdvAbortQueue(asc_dvc, scsiq) \
3192 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
3193 (ADV_DCNT) (scsiq))
3194
3195/*
3196 * Send a Bus Device Reset Message to the specified target ID.
3197 *
3198 * All outstanding commands will be purged if sending the
3199 * Bus Device Reset Message is successful.
3200 *
3201 * Return Value:
3202 * ADV_TRUE(1) - All requests on the target are purged.
3203 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
3204 * are not purged.
3205 */
3206#define AdvResetDevice(asc_dvc, target_id) \
3207 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
3208 (ADV_DCNT) (target_id))
3209
3210/*
3211 * SCSI Wide Type definition.
3212 */
3213#define ADV_SCSI_BIT_ID_TYPE ushort
3214
3215/*
3216 * AdvInitScsiTarget() 'cntl_flag' options.
3217 */
3218#define ADV_SCAN_LUN 0x01
3219#define ADV_CAPINFO_NOLUN 0x02
3220
3221/*
3222 * Convert target id to target id bit mask.
3223 */
3224#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
3225
3226/*
3227 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
3228 */
3229
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003230#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231#define QD_NO_ERROR 0x01
3232#define QD_ABORTED_BY_HOST 0x02
3233#define QD_WITH_ERROR 0x04
3234
3235#define QHSTA_NO_ERROR 0x00
3236#define QHSTA_M_SEL_TIMEOUT 0x11
3237#define QHSTA_M_DATA_OVER_RUN 0x12
3238#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
3239#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003240#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
3241#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
3242#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
3243#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
3244#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
3245#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
3246#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003248#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
3249#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
3250#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
3251#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
3252#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
3253#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
3254#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
3255#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256#define QHSTA_M_WTM_TIMEOUT 0x41
3257#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
3258#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
3259#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003260#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
3261#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
3262#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263
3264/*
3265 * Default EEPROM Configuration structure defined in a_init.c.
3266 */
3267static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
3268static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
3269static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
3270
3271/*
3272 * DvcGetPhyAddr() flag arguments
3273 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003274#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
3275#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
3276#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
3277#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
3278#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
3279#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280
3281/* Return the address that is aligned at the next doubleword >= to 'addr'. */
3282#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
3283#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
3284#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
3285
3286/*
3287 * Total contiguous memory needed for driver SG blocks.
3288 *
3289 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
3290 * number of scatter-gather elements the driver supports in a
3291 * single request.
3292 */
3293
3294#define ADV_SG_LIST_MAX_BYTE_SIZE \
3295 (sizeof(ADV_SG_BLOCK) * \
3296 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
3297
3298/*
3299 * Inquiry data structure and bitfield macros
3300 *
3301 * Using bitfields to access the subchar data isn't portable across
3302 * endianness, so instead mask and shift. Only quantities of more
3303 * than 1 bit are shifted, since the others are just tested for true
3304 * or false.
3305 */
3306
3307#define ADV_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
3308#define ADV_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
3309#define ADV_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
3310#define ADV_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
3311#define ADV_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
3312#define ADV_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
3313#define ADV_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
3314#define ADV_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
3315#define ADV_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
3316#define ADV_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
3317#define ADV_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
3318#define ADV_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
3319#define ADV_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
3320#define ADV_INQ_SYNC(inq) ((inq)->flags & 0x10)
3321#define ADV_INQ_WIDE16(inq) ((inq)->flags & 0x20)
3322#define ADV_INQ_WIDE32(inq) ((inq)->flags & 0x40)
3323#define ADV_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
3324#define ADV_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
3325#define ADV_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
3326#define ADV_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
3327
3328typedef struct {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003329 uchar periph; /* peripheral device type [0:4] */
3330 /* peripheral qualifier [5:7] */
3331 uchar devtype; /* device type modifier (for SCSI I) [0:6] */
3332 /* RMB - removable medium bit [7] */
3333 uchar ver; /* ANSI approved version [0:2] */
3334 /* ECMA version [3:5] */
3335 /* ISO version [6:7] */
3336 uchar byte3; /* response data format [0:3] */
3337 /* 0 SCSI 1 */
3338 /* 1 CCS */
3339 /* 2 SCSI-2 */
3340 /* 3-F reserved */
3341 /* reserved [4:5] */
3342 /* terminate I/O process bit (see 5.6.22) [6] */
3343 /* asynch. event notification (processor) [7] */
3344 uchar add_len; /* additional length */
3345 uchar res1; /* reserved */
3346 uchar res2; /* reserved */
3347 uchar flags; /* soft reset implemented [0] */
3348 /* command queuing [1] */
3349 /* reserved [2] */
3350 /* linked command for this logical unit [3] */
3351 /* synchronous data transfer [4] */
3352 /* wide bus 16 bit data transfer [5] */
3353 /* wide bus 32 bit data transfer [6] */
3354 /* relative addressing mode [7] */
3355 uchar vendor_id[8]; /* vendor identification */
3356 uchar product_id[16]; /* product identification */
3357 uchar product_rev_level[4]; /* product revision level */
3358 uchar vendor_specific[20]; /* vendor specific */
3359 uchar info; /* information unit supported [0] */
3360 /* quick arbitrate supported [1] */
3361 /* clocking field [2:3] */
3362 /* reserved [4:7] */
3363 uchar res3; /* reserved */
3364} ADV_SCSI_INQUIRY; /* 58 bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365
3366/*
3367 * --- Driver Constants and Macros
3368 */
3369
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370/* Reference Scsi_Host hostdata */
3371#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
3372
3373/* asc_board_t flags */
3374#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003375#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376#define ASC_SELECT_QUEUE_DEPTHS 0x08
3377
3378#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
3379#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
3380
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003381#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003383#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384
3385#ifdef CONFIG_PROC_FS
3386/* /proc/scsi/advansys/[0...] related definitions */
3387#define ASC_PRTBUF_SIZE 2048
3388#define ASC_PRTLINE_SIZE 160
3389
3390#define ASC_PRT_NEXT() \
3391 if (cp) { \
3392 totlen += len; \
3393 leftlen -= len; \
3394 if (leftlen == 0) { \
3395 return totlen; \
3396 } \
3397 cp += len; \
3398 }
3399#endif /* CONFIG_PROC_FS */
3400
3401/* Asc Library return codes */
3402#define ASC_TRUE 1
3403#define ASC_FALSE 0
3404#define ASC_NOERROR 1
3405#define ASC_BUSY 0
3406#define ASC_ERROR (-1)
3407
3408/* struct scsi_cmnd function return codes */
3409#define STATUS_BYTE(byte) (byte)
3410#define MSG_BYTE(byte) ((byte) << 8)
3411#define HOST_BYTE(byte) ((byte) << 16)
3412#define DRIVER_BYTE(byte) ((byte) << 24)
3413
3414/*
3415 * The following definitions and macros are OS independent interfaces to
3416 * the queue functions:
3417 * REQ - SCSI request structure
3418 * REQP - pointer to SCSI request structure
3419 * REQPTID(reqp) - reqp's target id
3420 * REQPNEXT(reqp) - reqp's next pointer
3421 * REQPNEXTP(reqp) - pointer to reqp's next pointer
3422 * REQPTIME(reqp) - reqp's time stamp value
3423 * REQTIMESTAMP() - system time stamp value
3424 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003425typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
3427#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
3428#define REQPTID(reqp) ((reqp)->device->id)
3429#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
3430#define REQTIMESTAMP() (jiffies)
3431
3432#define REQTIMESTAT(function, ascq, reqp, tid) \
3433{ \
3434 /*
3435 * If the request time stamp is less than the system time stamp, then \
3436 * maybe the system time stamp wrapped. Set the request time to zero.\
3437 */ \
3438 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
3439 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
3440 } else { \
3441 /* Indicate an error occurred with the assertion. */ \
3442 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
3443 REQPTIME(reqp) = 0; \
3444 } \
3445 /* Handle first minimum time case without external initialization. */ \
3446 if (((ascq)->q_tot_cnt[tid] == 1) || \
3447 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
3448 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
3449 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
3450 (function), (tid), (ascq)->q_min_tim[tid]); \
3451 } \
3452 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
3453 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
3454 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
3455 (function), tid, (ascq)->q_max_tim[tid]); \
3456 } \
3457 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
3458 /* Reset the time stamp field. */ \
3459 REQPTIME(reqp) = 0; \
3460}
3461
3462/* asc_enqueue() flags */
3463#define ASC_FRONT 1
3464#define ASC_BACK 2
3465
3466/* asc_dequeue_list() argument */
3467#define ASC_TID_ALL (-1)
3468
3469/* Return non-zero, if the queue is empty. */
3470#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
3471
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003473#define ASC_STATS(shost, counter)
3474#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003476#define ASC_STATS(shost, counter) \
3477 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003479#define ASC_STATS_ADD(shost, counter, count) \
3480 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481#endif /* ADVANSYS_STATS */
3482
3483#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
3484
3485/* If the result wraps when calculating tenths, return 0. */
3486#define ASC_TENTHS(num, den) \
3487 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
3488 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
3489
3490/*
3491 * Display a message to the console.
3492 */
3493#define ASC_PRINT(s) \
3494 { \
3495 printk("advansys: "); \
3496 printk(s); \
3497 }
3498
3499#define ASC_PRINT1(s, a1) \
3500 { \
3501 printk("advansys: "); \
3502 printk((s), (a1)); \
3503 }
3504
3505#define ASC_PRINT2(s, a1, a2) \
3506 { \
3507 printk("advansys: "); \
3508 printk((s), (a1), (a2)); \
3509 }
3510
3511#define ASC_PRINT3(s, a1, a2, a3) \
3512 { \
3513 printk("advansys: "); \
3514 printk((s), (a1), (a2), (a3)); \
3515 }
3516
3517#define ASC_PRINT4(s, a1, a2, a3, a4) \
3518 { \
3519 printk("advansys: "); \
3520 printk((s), (a1), (a2), (a3), (a4)); \
3521 }
3522
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523#ifndef ADVANSYS_DEBUG
3524
3525#define ASC_DBG(lvl, s)
3526#define ASC_DBG1(lvl, s, a1)
3527#define ASC_DBG2(lvl, s, a1, a2)
3528#define ASC_DBG3(lvl, s, a1, a2, a3)
3529#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
3530#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
3531#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
3532#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
3533#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3534#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
3535#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3536#define ASC_DBG_PRT_HEX(lvl, name, start, length)
3537#define ASC_DBG_PRT_CDB(lvl, cdb, len)
3538#define ASC_DBG_PRT_SENSE(lvl, sense, len)
3539#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
3540
3541#else /* ADVANSYS_DEBUG */
3542
3543/*
3544 * Debugging Message Levels:
3545 * 0: Errors Only
3546 * 1: High-Level Tracing
3547 * 2-N: Verbose Tracing
3548 */
3549
3550#define ASC_DBG(lvl, s) \
3551 { \
3552 if (asc_dbglvl >= (lvl)) { \
3553 printk(s); \
3554 } \
3555 }
3556
3557#define ASC_DBG1(lvl, s, a1) \
3558 { \
3559 if (asc_dbglvl >= (lvl)) { \
3560 printk((s), (a1)); \
3561 } \
3562 }
3563
3564#define ASC_DBG2(lvl, s, a1, a2) \
3565 { \
3566 if (asc_dbglvl >= (lvl)) { \
3567 printk((s), (a1), (a2)); \
3568 } \
3569 }
3570
3571#define ASC_DBG3(lvl, s, a1, a2, a3) \
3572 { \
3573 if (asc_dbglvl >= (lvl)) { \
3574 printk((s), (a1), (a2), (a3)); \
3575 } \
3576 }
3577
3578#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
3579 { \
3580 if (asc_dbglvl >= (lvl)) { \
3581 printk((s), (a1), (a2), (a3), (a4)); \
3582 } \
3583 }
3584
3585#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
3586 { \
3587 if (asc_dbglvl >= (lvl)) { \
3588 asc_prt_scsi_host(s); \
3589 } \
3590 }
3591
3592#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
3593 { \
3594 if (asc_dbglvl >= (lvl)) { \
3595 asc_prt_scsi_cmnd(s); \
3596 } \
3597 }
3598
3599#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
3600 { \
3601 if (asc_dbglvl >= (lvl)) { \
3602 asc_prt_asc_scsi_q(scsiqp); \
3603 } \
3604 }
3605
3606#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
3607 { \
3608 if (asc_dbglvl >= (lvl)) { \
3609 asc_prt_asc_qdone_info(qdone); \
3610 } \
3611 }
3612
3613#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
3614 { \
3615 if (asc_dbglvl >= (lvl)) { \
3616 asc_prt_adv_scsi_req_q(scsiqp); \
3617 } \
3618 }
3619
3620#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
3621 { \
3622 if (asc_dbglvl >= (lvl)) { \
3623 asc_prt_hex((name), (start), (length)); \
3624 } \
3625 }
3626
3627#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
3628 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
3629
3630#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
3631 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
3632
3633#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
3634 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
3635#endif /* ADVANSYS_DEBUG */
3636
3637#ifndef ADVANSYS_ASSERT
3638#define ASC_ASSERT(a)
3639#else /* ADVANSYS_ASSERT */
3640
3641#define ASC_ASSERT(a) \
3642 { \
3643 if (!(a)) { \
3644 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
3645 __FILE__, __LINE__); \
3646 } \
3647 }
3648
3649#endif /* ADVANSYS_ASSERT */
3650
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651/*
3652 * --- Driver Structures
3653 */
3654
3655#ifdef ADVANSYS_STATS
3656
3657/* Per board statistics structure */
3658struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003659 /* Driver Entrypoint Statistics */
3660 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
3661 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
3662 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
3663 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
3664 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
3665 ADV_DCNT done; /* # calls to request's scsi_done function */
3666 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
3667 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
3668 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
3669 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
3670 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
3671 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
3672 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
3673 ADV_DCNT exe_unknown; /* # unknown returns. */
3674 /* Data Transfer Statistics */
3675 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
3676 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
3677 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
3678 ADV_DCNT sg_elem; /* # scatter-gather elements */
3679 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680};
3681#endif /* ADVANSYS_STATS */
3682
3683/*
3684 * Request queuing structure
3685 */
3686typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003687 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
3688 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
3689 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003691 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
3692 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
3693 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
3694 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
3695 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
3696 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
3697#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698} asc_queue_t;
3699
3700/*
3701 * Adv Library Request Structures
3702 *
3703 * The following two structures are used to process Wide Board requests.
3704 *
3705 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
3706 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
3707 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
3708 * Mid-Level SCSI request structure.
3709 *
3710 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
3711 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
3712 * up to 255 scatter-gather elements may be used per request or
3713 * ADV_SCSI_REQ_Q.
3714 *
3715 * Both structures must be 32 byte aligned.
3716 */
3717typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003718 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
3719 uchar align[32]; /* Sgblock structure padding. */
3720 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721} adv_sgblk_t;
3722
3723typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003724 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
3725 uchar align[32]; /* Request structure padding. */
3726 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
3727 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
3728 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729} adv_req_t;
3730
3731/*
3732 * Structure allocated for each board.
3733 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003734 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 * of the 'Scsi_Host' structure starting at the 'hostdata'
3736 * field. It is guaranteed to be allocated from DMA-able memory.
3737 */
3738typedef struct asc_board {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003739 int id; /* Board Id */
3740 uint flags; /* Board flags */
3741 union {
3742 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
3743 ADV_DVC_VAR adv_dvc_var; /* Wide board */
3744 } dvc_var;
3745 union {
3746 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
3747 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
3748 } dvc_cfg;
3749 ushort asc_n_io_port; /* Number I/O ports. */
3750 asc_queue_t active; /* Active command queue */
3751 asc_queue_t waiting; /* Waiting command queue */
3752 asc_queue_t done; /* Done command queue */
3753 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
3754 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
3755 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
3756 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
3757 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
3758 union {
3759 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
3760 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
3761 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
3762 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
3763 } eep_config;
3764 ulong last_reset; /* Saved last reset time */
3765 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003766 /* /proc/scsi/advansys/[0...] */
3767 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003769 struct asc_stats asc_stats; /* Board statistics */
3770#endif /* ADVANSYS_STATS */
3771 /*
3772 * The following fields are used only for Narrow Boards.
3773 */
3774 /* The following three structures must be in DMA-able memory. */
3775 ASC_SCSI_REQ_Q scsireqq;
3776 ASC_CAP_INFO cap_info;
3777 ASC_SCSI_INQUIRY inquiry;
3778 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3779 /*
3780 * The following fields are used only for Wide Boards.
3781 */
3782 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3783 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06003784 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003785 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3786 adv_req_t *adv_reqp; /* Request structures. */
3787 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3788 ushort bios_signature; /* BIOS Signature. */
3789 ushort bios_version; /* BIOS Version. */
3790 ushort bios_codeseg; /* BIOS Code Segment. */
3791 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792} asc_board_t;
3793
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06003795static int asc_board_count;
3796
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003798static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799
3800/*
3801 * Global structures required to issue a command.
3802 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003803static ASC_SCSI_Q asc_scsi_q = { {0} };
3804static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003807static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808#endif /* ADVANSYS_DEBUG */
3809
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810/*
3811 * --- Driver Function Prototypes
3812 *
3813 * advansys.h contains function prototypes for functions global to Linux.
3814 */
3815
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003816static int advansys_slave_configure(struct scsi_device *);
3817static void asc_scsi_done_list(struct scsi_cmnd *);
3818static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3819static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3820static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3821static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
3822static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
3823static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3824static void adv_async_callback(ADV_DVC_VAR *, uchar);
3825static void asc_enqueue(asc_queue_t *, REQP, int);
3826static REQP asc_dequeue(asc_queue_t *, int);
3827static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3828static int asc_rmqueue(asc_queue_t *, REQP);
3829static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003831static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3832static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3833static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3834static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3835static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3836static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3837static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3838static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3839static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3840static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841#endif /* CONFIG_PROC_FS */
3842
3843/* Declaration for Asc Library internal functions referenced by driver. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003844static int AscFindSignature(PortAddr);
3845static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846
3847/* Statistics function prototypes. */
3848#ifdef ADVANSYS_STATS
3849#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003850static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3851static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852#endif /* CONFIG_PROC_FS */
3853#endif /* ADVANSYS_STATS */
3854
3855/* Debug function prototypes. */
3856#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003857static void asc_prt_scsi_host(struct Scsi_Host *);
3858static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
3859static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
3860static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
3861static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
3862static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
3863static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
3864static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
3865static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
3866static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
3867static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868#endif /* ADVANSYS_DEBUG */
3869
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870#ifdef CONFIG_PROC_FS
3871/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06003872 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 *
3874 * *buffer: I/O buffer
3875 * **start: if inout == FALSE pointer into buffer where user read should start
3876 * offset: current offset into a /proc/scsi/advansys/[0...] file
3877 * length: length of buffer
3878 * hostno: Scsi_Host host_no
3879 * inout: TRUE - user is writing; FALSE - user is reading
3880 *
3881 * Return the number of bytes read from or written to a
3882 * /proc/scsi/advansys/[0...] file.
3883 *
3884 * Note: This function uses the per board buffer 'prtbuf' which is
3885 * allocated when the board is initialized in advansys_detect(). The
3886 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
3887 * used to write to the buffer. The way asc_proc_copy() is written
3888 * if 'prtbuf' is too small it will not be overwritten. Instead the
3889 * user just won't get all the available statistics.
3890 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003891static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003893 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003895 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003896 char *cp;
3897 int cplen;
3898 int cnt;
3899 int totcnt;
3900 int leftlen;
3901 char *curbuf;
3902 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003904 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905#endif /* ADVANSYS_STATS */
3906
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003907 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003909 /*
3910 * User write not supported.
3911 */
3912 if (inout == TRUE) {
3913 return (-ENOSYS);
3914 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003916 /*
3917 * User read of /proc/scsi/advansys/[0...] file.
3918 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919
Matthew Wilcox2a437952007-07-26 11:00:51 -04003920 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003922 /* Copy read data starting at the beginning of the buffer. */
3923 *start = buffer;
3924 curbuf = buffer;
3925 advoffset = 0;
3926 totcnt = 0;
3927 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003929 /*
3930 * Get board configuration information.
3931 *
3932 * advansys_info() returns the board string from its own static buffer.
3933 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04003934 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003935 strcat(cp, "\n");
3936 cplen = strlen(cp);
3937 /* Copy board information. */
3938 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3939 totcnt += cnt;
3940 leftlen -= cnt;
3941 if (leftlen == 0) {
3942 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3943 return totcnt;
3944 }
3945 advoffset += cplen;
3946 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003948 /*
3949 * Display Wide Board BIOS Information.
3950 */
3951 if (ASC_WIDE_BOARD(boardp)) {
3952 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003953 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003954 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3955 cnt =
3956 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
3957 cplen);
3958 totcnt += cnt;
3959 leftlen -= cnt;
3960 if (leftlen == 0) {
3961 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3962 return totcnt;
3963 }
3964 advoffset += cplen;
3965 curbuf += cnt;
3966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003968 /*
3969 * Display driver information for each device attached to the board.
3970 */
3971 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003972 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003973 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3974 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3975 totcnt += cnt;
3976 leftlen -= cnt;
3977 if (leftlen == 0) {
3978 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3979 return totcnt;
3980 }
3981 advoffset += cplen;
3982 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003984 /*
3985 * Display EEPROM configuration for the board.
3986 */
3987 cp = boardp->prtbuf;
3988 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003989 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003990 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003991 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003992 }
3993 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3994 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3995 totcnt += cnt;
3996 leftlen -= cnt;
3997 if (leftlen == 0) {
3998 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3999 return totcnt;
4000 }
4001 advoffset += cplen;
4002 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004004 /*
4005 * Display driver configuration and information for the board.
4006 */
4007 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004008 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004009 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4010 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4011 totcnt += cnt;
4012 leftlen -= cnt;
4013 if (leftlen == 0) {
4014 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4015 return totcnt;
4016 }
4017 advoffset += cplen;
4018 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019
4020#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004021 /*
4022 * Display driver statistics for the board.
4023 */
4024 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004025 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004026 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4027 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4028 totcnt += cnt;
4029 leftlen -= cnt;
4030 if (leftlen == 0) {
4031 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4032 return totcnt;
4033 }
4034 advoffset += cplen;
4035 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004037 /*
4038 * Display driver statistics for each target.
4039 */
4040 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
4041 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004042 cplen = asc_prt_target_stats(shost, tgt_id, cp,
4043 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004044 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4045 cnt =
4046 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
4047 cplen);
4048 totcnt += cnt;
4049 leftlen -= cnt;
4050 if (leftlen == 0) {
4051 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4052 return totcnt;
4053 }
4054 advoffset += cplen;
4055 curbuf += cnt;
4056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057#endif /* ADVANSYS_STATS */
4058
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004059 /*
4060 * Display Asc Library dynamic configuration information
4061 * for the board.
4062 */
4063 cp = boardp->prtbuf;
4064 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004065 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004066 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004067 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004068 }
4069 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4070 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4071 totcnt += cnt;
4072 leftlen -= cnt;
4073 if (leftlen == 0) {
4074 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4075 return totcnt;
4076 }
4077 advoffset += cplen;
4078 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004080 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004082 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083}
4084#endif /* CONFIG_PROC_FS */
4085
4086/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 * advansys_info()
4088 *
4089 * Return suitable for printing on the console with the argument
4090 * adapter's configuration information.
4091 *
4092 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
4093 * otherwise the static 'info' array will be overrun.
4094 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004095static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004097 static char info[ASC_INFO_SIZE];
4098 asc_board_t *boardp;
4099 ASC_DVC_VAR *asc_dvc_varp;
4100 ADV_DVC_VAR *adv_dvc_varp;
4101 char *busname;
4102 int iolen;
4103 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004105 boardp = ASC_BOARDP(shost);
4106 if (ASC_NARROW_BOARD(boardp)) {
4107 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
4108 ASC_DBG(1, "advansys_info: begin\n");
4109 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
4110 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
4111 ASC_IS_ISAPNP) {
4112 busname = "ISA PnP";
4113 } else {
4114 busname = "ISA";
4115 }
4116 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4117 sprintf(info,
4118 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
4119 ASC_VERSION, busname,
4120 (ulong)shost->io_port,
4121 (ulong)shost->io_port + boardp->asc_n_io_port -
4122 1, shost->irq, shost->dma_channel);
4123 } else {
4124 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
4125 busname = "VL";
4126 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
4127 busname = "EISA";
4128 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
4129 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
4130 == ASC_IS_PCI_ULTRA) {
4131 busname = "PCI Ultra";
4132 } else {
4133 busname = "PCI";
4134 }
4135 } else {
4136 busname = "?";
4137 ASC_PRINT2
4138 ("advansys_info: board %d: unknown bus type %d\n",
4139 boardp->id, asc_dvc_varp->bus_type);
4140 }
4141 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4142 sprintf(info,
4143 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
4144 ASC_VERSION, busname,
4145 (ulong)shost->io_port,
4146 (ulong)shost->io_port + boardp->asc_n_io_port -
4147 1, shost->irq);
4148 }
4149 } else {
4150 /*
4151 * Wide Adapter Information
4152 *
4153 * Memory-mapped I/O is used instead of I/O space to access
4154 * the adapter, but display the I/O Port range. The Memory
4155 * I/O address is displayed through the driver /proc file.
4156 */
4157 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4158 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4159 iolen = ADV_3550_IOLEN;
4160 widename = "Ultra-Wide";
4161 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4162 iolen = ADV_38C0800_IOLEN;
4163 widename = "Ultra2-Wide";
4164 } else {
4165 iolen = ADV_38C1600_IOLEN;
4166 widename = "Ultra3-Wide";
4167 }
4168 sprintf(info,
4169 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
4170 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
4171 (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
4172 }
4173 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
4174 ASC_DBG(1, "advansys_info: end\n");
4175 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176}
4177
4178/*
4179 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
4180 *
4181 * This function always returns 0. Command return status is saved
4182 * in the 'scp' result field.
4183 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004184static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004185advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004187 struct Scsi_Host *shost;
4188 asc_board_t *boardp;
4189 ulong flags;
4190 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004192 shost = scp->device->host;
4193 boardp = ASC_BOARDP(shost);
4194 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004196 /* host_lock taken by mid-level prior to call but need to protect */
4197 /* against own ISR */
4198 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004200 /*
4201 * Block new commands while handling a reset or abort request.
4202 */
4203 if (boardp->flags & ASC_HOST_IN_RESET) {
4204 ASC_DBG1(1,
4205 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4206 (ulong)scp);
4207 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004209 /*
4210 * Add blocked requests to the board's 'done' queue. The queued
4211 * requests will be completed at the end of the abort or reset
4212 * handling.
4213 */
4214 asc_enqueue(&boardp->done, scp, ASC_BACK);
4215 spin_unlock_irqrestore(&boardp->lock, flags);
4216 return 0;
4217 }
4218
4219 /*
4220 * Attempt to execute any waiting commands for the board.
4221 */
4222 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4223 ASC_DBG(1,
4224 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4225 asc_execute_queue(&boardp->waiting);
4226 }
4227
4228 /*
4229 * Save the function pointer to Linux mid-level 'done' function
4230 * and attempt to execute the command.
4231 *
4232 * If ASC_NOERROR is returned the request has been added to the
4233 * board's 'active' queue and will be completed by the interrupt
4234 * handler.
4235 *
4236 * If ASC_BUSY is returned add the request to the board's per
4237 * target waiting list. This is the first time the request has
4238 * been tried. Add it to the back of the waiting list. It will be
4239 * retried later.
4240 *
4241 * If an error occurred, the request will have been placed on the
4242 * board's 'done' queue and must be completed before returning.
4243 */
4244 scp->scsi_done = done;
4245 switch (asc_execute_scsi_cmnd(scp)) {
4246 case ASC_NOERROR:
4247 break;
4248 case ASC_BUSY:
4249 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4250 break;
4251 case ASC_ERROR:
4252 default:
4253 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4254 /* Interrupts could be enabled here. */
4255 asc_scsi_done_list(done_scp);
4256 break;
4257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004260 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261}
4262
4263/*
4264 * advansys_reset()
4265 *
4266 * Reset the bus associated with the command 'scp'.
4267 *
4268 * This function runs its own thread. Interrupts must be blocked but
4269 * sleeping is allowed and no locking other than for host structures is
4270 * required. Returns SUCCESS or FAILED.
4271 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004272static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004274 struct Scsi_Host *shost;
4275 asc_board_t *boardp;
4276 ASC_DVC_VAR *asc_dvc_varp;
4277 ADV_DVC_VAR *adv_dvc_varp;
4278 ulong flags;
4279 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4280 struct scsi_cmnd *tscp, *new_last_scp;
4281 int status;
4282 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004284 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285
4286#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004287 if (scp->device->host != NULL) {
4288 ASC_STATS(scp->device->host, reset);
4289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290#endif /* ADVANSYS_STATS */
4291
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004292 if ((shost = scp->device->host) == NULL) {
4293 scp->result = HOST_BYTE(DID_ERROR);
4294 return FAILED;
4295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004297 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004299 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4300 boardp->id);
4301 /*
4302 * Check for re-entrancy.
4303 */
4304 spin_lock_irqsave(&boardp->lock, flags);
4305 if (boardp->flags & ASC_HOST_IN_RESET) {
4306 spin_unlock_irqrestore(&boardp->lock, flags);
4307 return FAILED;
4308 }
4309 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004312 if (ASC_NARROW_BOARD(boardp)) {
4313 /*
4314 * Narrow Board
4315 */
4316 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004318 /*
4319 * Reset the chip and SCSI bus.
4320 */
4321 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4322 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004324 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4325 if (asc_dvc_varp->err_code) {
4326 ASC_PRINT2
4327 ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
4328 boardp->id, asc_dvc_varp->err_code);
4329 ret = FAILED;
4330 } else if (status) {
4331 ASC_PRINT2
4332 ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
4333 boardp->id, status);
4334 } else {
4335 ASC_PRINT1
4336 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4337 boardp->id);
4338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004340 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4341 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004343 } else {
4344 /*
4345 * Wide Board
4346 *
4347 * If the suggest reset bus flags are set, then reset the bus.
4348 * Otherwise only reset the device.
4349 */
4350 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004352 /*
4353 * Reset the target's SCSI bus.
4354 */
4355 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4356 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4357 case ASC_TRUE:
4358 ASC_PRINT1
4359 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4360 boardp->id);
4361 break;
4362 case ASC_FALSE:
4363 default:
4364 ASC_PRINT1
4365 ("advansys_reset: board %d: SCSI bus reset error.\n",
4366 boardp->id);
4367 ret = FAILED;
4368 break;
4369 }
4370 spin_lock_irqsave(&boardp->lock, flags);
4371 (void)AdvISR(adv_dvc_varp);
4372 }
4373 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004375 /*
4376 * Dequeue all board 'done' requests. A pointer to the last request
4377 * is returned in 'last_scp'.
4378 */
4379 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004381 /*
4382 * Dequeue all board 'active' requests for all devices and set
4383 * the request status to DID_RESET. A pointer to the last request
4384 * is returned in 'last_scp'.
4385 */
4386 if (done_scp == NULL) {
4387 done_scp =
4388 asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
4389 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4390 tscp->result = HOST_BYTE(DID_RESET);
4391 }
4392 } else {
4393 /* Append to 'done_scp' at the end with 'last_scp'. */
4394 ASC_ASSERT(last_scp != NULL);
4395 last_scp->host_scribble =
4396 (unsigned char *)asc_dequeue_list(&boardp->active,
4397 &new_last_scp,
4398 ASC_TID_ALL);
4399 if (new_last_scp != NULL) {
4400 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4401 for (tscp = REQPNEXT(last_scp); tscp;
4402 tscp = REQPNEXT(tscp)) {
4403 tscp->result = HOST_BYTE(DID_RESET);
4404 }
4405 last_scp = new_last_scp;
4406 }
4407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004409 /*
4410 * Dequeue all 'waiting' requests and set the request status
4411 * to DID_RESET.
4412 */
4413 if (done_scp == NULL) {
4414 done_scp =
4415 asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
4416 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4417 tscp->result = HOST_BYTE(DID_RESET);
4418 }
4419 } else {
4420 /* Append to 'done_scp' at the end with 'last_scp'. */
4421 ASC_ASSERT(last_scp != NULL);
4422 last_scp->host_scribble =
4423 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4424 &new_last_scp,
4425 ASC_TID_ALL);
4426 if (new_last_scp != NULL) {
4427 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4428 for (tscp = REQPNEXT(last_scp); tscp;
4429 tscp = REQPNEXT(tscp)) {
4430 tscp->result = HOST_BYTE(DID_RESET);
4431 }
4432 last_scp = new_last_scp;
4433 }
4434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004436 /* Save the time of the most recently completed reset. */
4437 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004439 /* Clear reset flag. */
4440 boardp->flags &= ~ASC_HOST_IN_RESET;
4441 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004443 /*
4444 * Complete all the 'done_scp' requests.
4445 */
4446 if (done_scp != NULL) {
4447 asc_scsi_done_list(done_scp);
4448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004450 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004452 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453}
4454
4455/*
4456 * advansys_biosparam()
4457 *
4458 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4459 * support is enabled for a drive.
4460 *
4461 * ip (information pointer) is an int array with the following definition:
4462 * ip[0]: heads
4463 * ip[1]: sectors
4464 * ip[2]: cylinders
4465 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004466static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004468 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004470 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004472 ASC_DBG(1, "advansys_biosparam: begin\n");
4473 ASC_STATS(sdev->host, biosparam);
4474 boardp = ASC_BOARDP(sdev->host);
4475 if (ASC_NARROW_BOARD(boardp)) {
4476 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4477 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4478 ip[0] = 255;
4479 ip[1] = 63;
4480 } else {
4481 ip[0] = 64;
4482 ip[1] = 32;
4483 }
4484 } else {
4485 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4486 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4487 ip[0] = 255;
4488 ip[1] = 63;
4489 } else {
4490 ip[0] = 64;
4491 ip[1] = 32;
4492 }
4493 }
4494 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4495 ASC_DBG(1, "advansys_biosparam: end\n");
4496 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497}
4498
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004499static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004500 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004502 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004504 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004505 .info = advansys_info,
4506 .queuecommand = advansys_queuecommand,
4507 .eh_bus_reset_handler = advansys_reset,
4508 .bios_param = advansys_biosparam,
4509 .slave_configure = advansys_slave_configure,
4510 /*
4511 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004512 * must be set. The flag will be cleared in advansys_board_found
4513 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004514 */
4515 .unchecked_isa_dma = 1,
4516 /*
4517 * All adapters controlled by this driver are capable of large
4518 * scatter-gather lists. According to the mid-level SCSI documentation
4519 * this obviates any performance gain provided by setting
4520 * 'use_clustering'. But empirically while CPU utilization is increased
4521 * by enabling clustering, I/O throughput increases as well.
4522 */
4523 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526/*
4527 * --- Miscellaneous Driver Functions
4528 */
4529
4530/*
4531 * First-level interrupt handler.
4532 *
4533 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4534 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4535 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4536 * to the AdvanSys driver which is for a device sharing an interrupt with
4537 * an AdvanSys adapter.
4538 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004539static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004541 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004542 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4543 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004544 struct Scsi_Host *shost = dev_id;
4545 asc_board_t *boardp = ASC_BOARDP(shost);
4546 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004548 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
4549 spin_lock_irqsave(&boardp->lock, flags);
4550 if (ASC_NARROW_BOARD(boardp)) {
4551 /*
4552 * Narrow Board
4553 */
4554 if (AscIsIntPending(shost->io_port)) {
4555 result = IRQ_HANDLED;
4556 ASC_STATS(shost, interrupt);
4557 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
4558 AscISR(&boardp->dvc_var.asc_dvc_var);
4559 }
4560 } else {
4561 /*
4562 * Wide Board
4563 */
4564 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4565 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4566 result = IRQ_HANDLED;
4567 ASC_STATS(shost, interrupt);
4568 }
4569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004571 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004572 * Start waiting requests and create a list of completed requests.
4573 *
4574 * If a reset request is being performed for the board, the reset
4575 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004576 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004577 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4578 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
4579 "last_scp 0x%p\n", done_scp, last_scp);
4580
4581 /* Start any waiting commands for the board. */
4582 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4583 ASC_DBG(1, "advansys_interrupt: before "
4584 "asc_execute_queue()\n");
4585 asc_execute_queue(&boardp->waiting);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004588 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004589 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004590 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004591 * 'done_scp' will always be NULL on the first iteration of
4592 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004593 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004594 if (done_scp == NULL) {
4595 done_scp = asc_dequeue_list(&boardp->done,
4596 &last_scp, ASC_TID_ALL);
4597 } else {
4598 ASC_ASSERT(last_scp != NULL);
4599 last_scp->host_scribble =
4600 (unsigned char *)asc_dequeue_list(&boardp->
4601 done,
4602 &new_last_scp,
4603 ASC_TID_ALL);
4604 if (new_last_scp != NULL) {
4605 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4606 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004607 }
4608 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004609 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004610 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004612 /*
4613 * If interrupts were enabled on entry, then they
4614 * are now enabled here.
4615 *
4616 * Complete all requests on the done list.
4617 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004619 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004621 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004622 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623}
4624
4625/*
4626 * Set the number of commands to queue per device for the
4627 * specified host adapter.
4628 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004629static int advansys_slave_configure(struct scsi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004631 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004633 boardp = ASC_BOARDP(device->host);
4634 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
4635 /*
4636 * Save a pointer to the device and set its initial/maximum
4637 * queue depth. Only save the pointer for a lun0 dev though.
4638 */
4639 if (device->lun == 0)
4640 boardp->device[device->id] = device;
4641 if (device->tagged_supported) {
4642 if (ASC_NARROW_BOARD(boardp)) {
4643 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4644 boardp->dvc_var.asc_dvc_var.
4645 max_dvc_qng[device->id]);
4646 } else {
4647 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4648 boardp->dvc_var.adv_dvc_var.
4649 max_dvc_qng);
4650 }
4651 } else {
4652 scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
4653 }
4654 ASC_DBG4(1,
4655 "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
4656 (ulong)device, (ulong)boardp, device->id, device->queue_depth);
4657 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658}
4659
4660/*
4661 * Complete all requests on the singly linked list pointed
4662 * to by 'scp'.
4663 *
4664 * Interrupts can be enabled on entry.
4665 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004666static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004668 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004670 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4671 while (scp != NULL) {
4672 asc_board_t *boardp;
4673 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004675 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4676 tscp = REQPNEXT(scp);
4677 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004679 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004681 if (ASC_NARROW_BOARD(boardp))
4682 dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
4683 else
4684 dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004686 if (scp->use_sg)
4687 dma_unmap_sg(dev,
4688 (struct scatterlist *)scp->request_buffer,
4689 scp->use_sg, scp->sc_data_direction);
4690 else if (scp->request_bufflen)
4691 dma_unmap_single(dev, scp->SCp.dma_handle,
4692 scp->request_bufflen,
4693 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004695 ASC_STATS(scp->device->host, done);
4696 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004698 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004700 scp = tscp;
4701 }
4702 ASC_DBG(2, "asc_scsi_done_list: done\n");
4703 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704}
4705
4706/*
4707 * Execute a single 'Scsi_Cmnd'.
4708 *
4709 * The function 'done' is called when the request has been completed.
4710 *
4711 * Scsi_Cmnd:
4712 *
4713 * host - board controlling device
4714 * device - device to send command
4715 * target - target of device
4716 * lun - lun of device
4717 * cmd_len - length of SCSI CDB
4718 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4719 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4720 *
4721 * if (use_sg == 0) {
4722 * request_buffer - buffer address for request
4723 * request_bufflen - length of request buffer
4724 * } else {
4725 * request_buffer - pointer to scatterlist structure
4726 * }
4727 *
4728 * sense_buffer - sense command buffer
4729 *
4730 * result (4 bytes of an int):
4731 * Byte Meaning
4732 * 0 SCSI Status Byte Code
4733 * 1 SCSI One Byte Message Code
4734 * 2 Host Error Code
4735 * 3 Mid-Level Error Code
4736 *
4737 * host driver fields:
4738 * SCp - Scsi_Pointer used for command processing status
4739 * scsi_done - used to save caller's done function
4740 * host_scribble - used for pointer to another struct scsi_cmnd
4741 *
4742 * If this function returns ASC_NOERROR the request has been enqueued
4743 * on the board's 'active' queue and will be completed from the
4744 * interrupt handler.
4745 *
4746 * If this function returns ASC_NOERROR the request has been enqueued
4747 * on the board's 'done' queue and must be completed by the caller.
4748 *
4749 * If ASC_BUSY is returned the request will be enqueued by the
4750 * caller on the target's waiting queue and re-tried later.
4751 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004752static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004754 asc_board_t *boardp;
4755 ASC_DVC_VAR *asc_dvc_varp;
4756 ADV_DVC_VAR *adv_dvc_varp;
4757 ADV_SCSI_REQ_Q *adv_scsiqp;
4758 struct scsi_device *device;
4759 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004761 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4762 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004764 boardp = ASC_BOARDP(scp->device->host);
4765 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004767 if (ASC_NARROW_BOARD(boardp)) {
4768 /*
4769 * Build and execute Narrow Board request.
4770 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004772 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004774 /*
4775 * Build Asc Library request structure using the
4776 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4777 *
4778 * If an error is returned, then the request has been
4779 * queued on the board done queue. It will be completed
4780 * by the caller.
4781 *
4782 * asc_build_req() can not return ASC_BUSY.
4783 */
4784 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4785 ASC_STATS(scp->device->host, build_error);
4786 return ASC_ERROR;
4787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004789 /*
4790 * Execute the command. If there is no error, add the command
4791 * to the active queue.
4792 */
4793 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4794 case ASC_NOERROR:
4795 ASC_STATS(scp->device->host, exe_noerror);
4796 /*
4797 * Increment monotonically increasing per device successful
4798 * request counter. Wrapping doesn't matter.
4799 */
4800 boardp->reqcnt[scp->device->id]++;
4801 asc_enqueue(&boardp->active, scp, ASC_BACK);
4802 ASC_DBG(1,
4803 "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
4804 break;
4805 case ASC_BUSY:
4806 /*
4807 * Caller will enqueue request on the target's waiting queue
4808 * and retry later.
4809 */
4810 ASC_STATS(scp->device->host, exe_busy);
4811 break;
4812 case ASC_ERROR:
4813 ASC_PRINT2
4814 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4815 boardp->id, asc_dvc_varp->err_code);
4816 ASC_STATS(scp->device->host, exe_error);
4817 scp->result = HOST_BYTE(DID_ERROR);
4818 asc_enqueue(&boardp->done, scp, ASC_BACK);
4819 break;
4820 default:
4821 ASC_PRINT2
4822 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
4823 boardp->id, asc_dvc_varp->err_code);
4824 ASC_STATS(scp->device->host, exe_unknown);
4825 scp->result = HOST_BYTE(DID_ERROR);
4826 asc_enqueue(&boardp->done, scp, ASC_BACK);
4827 break;
4828 }
4829 } else {
4830 /*
4831 * Build and execute Wide Board request.
4832 */
4833 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004835 /*
4836 * Build and get a pointer to an Adv Library request structure.
4837 *
4838 * If the request is successfully built then send it below,
4839 * otherwise return with an error.
4840 */
4841 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4842 case ASC_NOERROR:
4843 ASC_DBG(3,
4844 "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
4845 break;
4846 case ASC_BUSY:
4847 ASC_DBG(1,
4848 "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
4849 /*
4850 * If busy is returned the request has not been enqueued.
4851 * It will be enqueued by the caller on the target's waiting
4852 * queue and retried later.
4853 *
4854 * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
4855 * count wide board busy conditions. They are updated in
4856 * adv_build_req and adv_get_sglist, respectively.
4857 */
4858 return ASC_BUSY;
4859 case ASC_ERROR:
4860 /*
4861 * If an error is returned, then the request has been
4862 * queued on the board done queue. It will be completed
4863 * by the caller.
4864 */
4865 default:
4866 ASC_DBG(1,
4867 "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
4868 ASC_STATS(scp->device->host, build_error);
4869 return ASC_ERROR;
4870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004872 /*
4873 * Execute the command. If there is no error, add the command
4874 * to the active queue.
4875 */
4876 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
4877 case ASC_NOERROR:
4878 ASC_STATS(scp->device->host, exe_noerror);
4879 /*
4880 * Increment monotonically increasing per device successful
4881 * request counter. Wrapping doesn't matter.
4882 */
4883 boardp->reqcnt[scp->device->id]++;
4884 asc_enqueue(&boardp->active, scp, ASC_BACK);
4885 ASC_DBG(1,
4886 "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
4887 break;
4888 case ASC_BUSY:
4889 /*
4890 * Caller will enqueue request on the target's waiting queue
4891 * and retry later.
4892 */
4893 ASC_STATS(scp->device->host, exe_busy);
4894 break;
4895 case ASC_ERROR:
4896 ASC_PRINT2
4897 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4898 boardp->id, adv_dvc_varp->err_code);
4899 ASC_STATS(scp->device->host, exe_error);
4900 scp->result = HOST_BYTE(DID_ERROR);
4901 asc_enqueue(&boardp->done, scp, ASC_BACK);
4902 break;
4903 default:
4904 ASC_PRINT2
4905 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
4906 boardp->id, adv_dvc_varp->err_code);
4907 ASC_STATS(scp->device->host, exe_unknown);
4908 scp->result = HOST_BYTE(DID_ERROR);
4909 asc_enqueue(&boardp->done, scp, ASC_BACK);
4910 break;
4911 }
4912 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004914 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
4915 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916}
4917
4918/*
4919 * Build a request structure for the Asc Library (Narrow Board).
4920 *
4921 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
4922 * used to build the request.
4923 *
4924 * If an error occurs, then queue the request on the board done
4925 * queue and return ASC_ERROR.
4926 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004927static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004928{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004929 struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004930
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004931 /*
4932 * Mutually exclusive access is required to 'asc_scsi_q' and
4933 * 'asc_sg_head' until after the request is started.
4934 */
4935 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004937 /*
4938 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
4939 */
4940 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004942 /*
4943 * Build the ASC_SCSI_Q request.
4944 *
4945 * For narrow boards a CDB length maximum of 12 bytes
4946 * is supported.
4947 */
4948 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
4949 ASC_PRINT3
4950 ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n",
4951 boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
4952 scp->result = HOST_BYTE(DID_ERROR);
4953 asc_enqueue(&boardp->done, scp, ASC_BACK);
4954 return ASC_ERROR;
4955 }
4956 asc_scsi_q.cdbptr = &scp->cmnd[0];
4957 asc_scsi_q.q2.cdb_len = scp->cmd_len;
4958 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
4959 asc_scsi_q.q1.target_lun = scp->device->lun;
4960 asc_scsi_q.q2.target_ix =
4961 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
4962 asc_scsi_q.q1.sense_addr =
4963 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4964 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004966 /*
4967 * If there are any outstanding requests for the current target,
4968 * then every 255th request send an ORDERED request. This heuristic
4969 * tries to retain the benefit of request sorting while preventing
4970 * request starvation. 255 is the max number of tags or pending commands
4971 * a device may have outstanding.
4972 *
4973 * The request count is incremented below for every successfully
4974 * started request.
4975 *
4976 */
4977 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
4978 (boardp->reqcnt[scp->device->id] % 255) == 0) {
4979 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
4980 } else {
4981 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
4982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004984 /*
4985 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
4986 * buffer command.
4987 */
4988 if (scp->use_sg == 0) {
4989 /*
4990 * CDB request of single contiguous buffer.
4991 */
4992 ASC_STATS(scp->device->host, cont_cnt);
4993 scp->SCp.dma_handle = scp->request_bufflen ?
4994 dma_map_single(dev, scp->request_buffer,
4995 scp->request_bufflen,
4996 scp->sc_data_direction) : 0;
4997 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
4998 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
4999 ASC_STATS_ADD(scp->device->host, cont_xfer,
5000 ASC_CEILING(scp->request_bufflen, 512));
5001 asc_scsi_q.q1.sg_queue_cnt = 0;
5002 asc_scsi_q.sg_head = NULL;
5003 } else {
5004 /*
5005 * CDB scatter-gather request list.
5006 */
5007 int sgcnt;
5008 int use_sg;
5009 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005011 slp = (struct scatterlist *)scp->request_buffer;
5012 use_sg =
5013 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005015 if (use_sg > scp->device->host->sg_tablesize) {
5016 ASC_PRINT3
5017 ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
5018 boardp->id, use_sg,
5019 scp->device->host->sg_tablesize);
5020 dma_unmap_sg(dev, slp, scp->use_sg,
5021 scp->sc_data_direction);
5022 scp->result = HOST_BYTE(DID_ERROR);
5023 asc_enqueue(&boardp->done, scp, ASC_BACK);
5024 return ASC_ERROR;
5025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005027 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005029 /*
5030 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
5031 * structure to point to it.
5032 */
5033 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005035 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5036 asc_scsi_q.sg_head = &asc_sg_head;
5037 asc_scsi_q.q1.data_cnt = 0;
5038 asc_scsi_q.q1.data_addr = 0;
5039 /* This is a byte value, otherwise it would need to be swapped. */
5040 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5041 ASC_STATS_ADD(scp->device->host, sg_elem,
5042 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005044 /*
5045 * Convert scatter-gather list into ASC_SG_HEAD list.
5046 */
5047 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5048 asc_sg_head.sg_list[sgcnt].addr =
5049 cpu_to_le32(sg_dma_address(slp));
5050 asc_sg_head.sg_list[sgcnt].bytes =
5051 cpu_to_le32(sg_dma_len(slp));
5052 ASC_STATS_ADD(scp->device->host, sg_xfer,
5053 ASC_CEILING(sg_dma_len(slp), 512));
5054 }
5055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005057 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5058 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005060 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061}
5062
5063/*
5064 * Build a request structure for the Adv Library (Wide Board).
5065 *
5066 * If an adv_req_t can not be allocated to issue the request,
5067 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5068 *
5069 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5070 * microcode for DMA addresses or math operations are byte swapped
5071 * to little-endian order.
5072 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005073static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005075 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005077 adv_req_t *reqp;
5078 ADV_SCSI_REQ_Q *scsiqp;
5079 int i;
5080 int ret;
5081 struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005083 /*
5084 * Allocate an adv_req_t structure from the board to execute
5085 * the command.
5086 */
5087 if (boardp->adv_reqp == NULL) {
5088 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5089 ASC_STATS(scp->device->host, adv_build_noreq);
5090 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005092 reqp = boardp->adv_reqp;
5093 boardp->adv_reqp = reqp->next_reqp;
5094 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005097 /*
5098 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5099 */
5100 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005102 /*
5103 * Initialize the structure.
5104 */
5105 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005107 /*
5108 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5109 */
5110 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005112 /*
5113 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5114 */
5115 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005117 /*
5118 * Build the ADV_SCSI_REQ_Q request.
5119 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005121 /*
5122 * Set CDB length and copy it to the request structure.
5123 * For wide boards a CDB length maximum of 16 bytes
5124 * is supported.
5125 */
5126 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5127 ASC_PRINT3
5128 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5129 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5130 scp->result = HOST_BYTE(DID_ERROR);
5131 asc_enqueue(&boardp->done, scp, ASC_BACK);
5132 return ASC_ERROR;
5133 }
5134 scsiqp->cdb_len = scp->cmd_len;
5135 /* Copy first 12 CDB bytes to cdb[]. */
5136 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5137 scsiqp->cdb[i] = scp->cmnd[i];
5138 }
5139 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5140 for (; i < scp->cmd_len; i++) {
5141 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005144 scsiqp->target_id = scp->device->id;
5145 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005147 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5148 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005150 /*
5151 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5152 * buffer command.
5153 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005155 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5156 scsiqp->vdata_addr = scp->request_buffer;
5157 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5158
5159 if (scp->use_sg == 0) {
5160 /*
5161 * CDB request of single contiguous buffer.
5162 */
5163 reqp->sgblkp = NULL;
5164 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5165 if (scp->request_bufflen) {
5166 scsiqp->vdata_addr = scp->request_buffer;
5167 scp->SCp.dma_handle =
5168 dma_map_single(dev, scp->request_buffer,
5169 scp->request_bufflen,
5170 scp->sc_data_direction);
5171 } else {
5172 scsiqp->vdata_addr = NULL;
5173 scp->SCp.dma_handle = 0;
5174 }
5175 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5176 scsiqp->sg_list_ptr = NULL;
5177 scsiqp->sg_real_addr = 0;
5178 ASC_STATS(scp->device->host, cont_cnt);
5179 ASC_STATS_ADD(scp->device->host, cont_xfer,
5180 ASC_CEILING(scp->request_bufflen, 512));
5181 } else {
5182 /*
5183 * CDB scatter-gather request list.
5184 */
5185 struct scatterlist *slp;
5186 int use_sg;
5187
5188 slp = (struct scatterlist *)scp->request_buffer;
5189 use_sg =
5190 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
5191
5192 if (use_sg > ADV_MAX_SG_LIST) {
5193 ASC_PRINT3
5194 ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
5195 boardp->id, use_sg,
5196 scp->device->host->sg_tablesize);
5197 dma_unmap_sg(dev, slp, scp->use_sg,
5198 scp->sc_data_direction);
5199 scp->result = HOST_BYTE(DID_ERROR);
5200 asc_enqueue(&boardp->done, scp, ASC_BACK);
5201
5202 /*
5203 * Free the 'adv_req_t' structure by adding it back to the
5204 * board free list.
5205 */
5206 reqp->next_reqp = boardp->adv_reqp;
5207 boardp->adv_reqp = reqp;
5208
5209 return ASC_ERROR;
5210 }
5211
5212 if ((ret =
5213 adv_get_sglist(boardp, reqp, scp,
5214 use_sg)) != ADV_SUCCESS) {
5215 /*
5216 * Free the adv_req_t structure by adding it back to the
5217 * board free list.
5218 */
5219 reqp->next_reqp = boardp->adv_reqp;
5220 boardp->adv_reqp = reqp;
5221
5222 return ret;
5223 }
5224
5225 ASC_STATS(scp->device->host, sg_cnt);
5226 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5227 }
5228
5229 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5230 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5231
5232 *adv_scsiqpp = scsiqp;
5233
5234 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235}
5236
5237/*
5238 * Build scatter-gather list for Adv Library (Wide Board).
5239 *
5240 * Additional ADV_SG_BLOCK structures will need to be allocated
5241 * if the total number of scatter-gather elements exceeds
5242 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5243 * assumed to be physically contiguous.
5244 *
5245 * Return:
5246 * ADV_SUCCESS(1) - SG List successfully created
5247 * ADV_ERROR(-1) - SG List creation failed
5248 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005249static int
5250adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5251 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005253 adv_sgblk_t *sgblkp;
5254 ADV_SCSI_REQ_Q *scsiqp;
5255 struct scatterlist *slp;
5256 int sg_elem_cnt;
5257 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5258 ADV_PADDR sg_block_paddr;
5259 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005261 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5262 slp = (struct scatterlist *)scp->request_buffer;
5263 sg_elem_cnt = use_sg;
5264 prev_sg_block = NULL;
5265 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005267 do {
5268 /*
5269 * Allocate a 'adv_sgblk_t' structure from the board free
5270 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5271 * (15) scatter-gather elements.
5272 */
5273 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5274 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5275 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005277 /*
5278 * Allocation failed. Free 'adv_sgblk_t' structures already
5279 * allocated for the request.
5280 */
5281 while ((sgblkp = reqp->sgblkp) != NULL) {
5282 /* Remove 'sgblkp' from the request list. */
5283 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005285 /* Add 'sgblkp' to the board free list. */
5286 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5287 boardp->adv_sgblkp = sgblkp;
5288 }
5289 return ASC_BUSY;
5290 } else {
5291 /* Complete 'adv_sgblk_t' board allocation. */
5292 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5293 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005295 /*
5296 * Get 8 byte aligned virtual and physical addresses for
5297 * the allocated ADV_SG_BLOCK structure.
5298 */
5299 sg_block =
5300 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5301 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005303 /*
5304 * Check if this is the first 'adv_sgblk_t' for the request.
5305 */
5306 if (reqp->sgblkp == NULL) {
5307 /* Request's first scatter-gather block. */
5308 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005310 /*
5311 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5312 * address pointers.
5313 */
5314 scsiqp->sg_list_ptr = sg_block;
5315 scsiqp->sg_real_addr =
5316 cpu_to_le32(sg_block_paddr);
5317 } else {
5318 /* Request's second or later scatter-gather block. */
5319 sgblkp->next_sgblkp = reqp->sgblkp;
5320 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005322 /*
5323 * Point the previous ADV_SG_BLOCK structure to
5324 * the newly allocated ADV_SG_BLOCK structure.
5325 */
5326 ASC_ASSERT(prev_sg_block != NULL);
5327 prev_sg_block->sg_ptr =
5328 cpu_to_le32(sg_block_paddr);
5329 }
5330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005332 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5333 sg_block->sg_list[i].sg_addr =
5334 cpu_to_le32(sg_dma_address(slp));
5335 sg_block->sg_list[i].sg_count =
5336 cpu_to_le32(sg_dma_len(slp));
5337 ASC_STATS_ADD(scp->device->host, sg_xfer,
5338 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005339
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005340 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5341 sg_block->sg_cnt = i + 1;
5342 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5343 return ADV_SUCCESS;
5344 }
5345 slp++;
5346 }
5347 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5348 prev_sg_block = sg_block;
5349 }
5350 while (1);
5351 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352}
5353
5354/*
5355 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5356 *
5357 * Interrupt callback function for the Narrow SCSI Asc Library.
5358 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005359static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005361 asc_board_t *boardp;
5362 struct scsi_cmnd *scp;
5363 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005365 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5366 (ulong)asc_dvc_varp, (ulong)qdonep);
5367 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005369 /*
5370 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5371 * command that has been completed.
5372 */
5373 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5374 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005376 if (scp == NULL) {
5377 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5378 return;
5379 }
5380 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005382 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005383 ASC_STATS(shost, callback);
5384 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005386 /*
5387 * If the request isn't found on the active queue, it may
5388 * have been removed to handle a reset request.
5389 * Display a message and return.
5390 */
5391 boardp = ASC_BOARDP(shost);
5392 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5393 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5394 ASC_PRINT2
5395 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5396 boardp->id, (ulong)scp);
5397 return;
5398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005400 /*
5401 * 'qdonep' contains the command's ending status.
5402 */
5403 switch (qdonep->d3.done_stat) {
5404 case QD_NO_ERROR:
5405 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5406 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005408 /*
5409 * If an INQUIRY command completed successfully, then call
5410 * the AscInquiryHandling() function to set-up the device.
5411 */
5412 if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
5413 (scp->request_bufflen - qdonep->remain_bytes) >= 8) {
5414 AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
5415 (ASC_SCSI_INQUIRY *)scp->
5416 request_buffer);
5417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005419 /*
5420 * Check for an underrun condition.
5421 *
5422 * If there was no error and an underrun condition, then
5423 * then return the number of underrun bytes.
5424 */
5425 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5426 qdonep->remain_bytes <= scp->request_bufflen) {
5427 ASC_DBG1(1,
5428 "asc_isr_callback: underrun condition %u bytes\n",
5429 (unsigned)qdonep->remain_bytes);
5430 scp->resid = qdonep->remain_bytes;
5431 }
5432 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005434 case QD_WITH_ERROR:
5435 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5436 switch (qdonep->d3.host_stat) {
5437 case QHSTA_NO_ERROR:
5438 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5439 ASC_DBG(2,
5440 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5441 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5442 sizeof(scp->sense_buffer));
5443 /*
5444 * Note: The 'status_byte()' macro used by target drivers
5445 * defined in scsi.h shifts the status byte returned by
5446 * host drivers right by 1 bit. This is why target drivers
5447 * also use right shifted status byte definitions. For
5448 * instance target drivers use CHECK_CONDITION, defined to
5449 * 0x1, instead of the SCSI defined check condition value
5450 * of 0x2. Host drivers are supposed to return the status
5451 * byte as it is defined by SCSI.
5452 */
5453 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5454 STATUS_BYTE(qdonep->d3.scsi_stat);
5455 } else {
5456 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5457 }
5458 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005460 default:
5461 /* QHSTA error occurred */
5462 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5463 qdonep->d3.host_stat);
5464 scp->result = HOST_BYTE(DID_BAD_TARGET);
5465 break;
5466 }
5467 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005469 case QD_ABORTED_BY_HOST:
5470 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5471 scp->result =
5472 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5473 scsi_msg) |
5474 STATUS_BYTE(qdonep->d3.scsi_stat);
5475 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005477 default:
5478 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5479 qdonep->d3.done_stat);
5480 scp->result =
5481 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5482 scsi_msg) |
5483 STATUS_BYTE(qdonep->d3.scsi_stat);
5484 break;
5485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005487 /*
5488 * If the 'init_tidmask' bit isn't already set for the target and the
5489 * current request finished normally, then set the bit for the target
5490 * to indicate that a device is present.
5491 */
5492 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5493 qdonep->d3.done_stat == QD_NO_ERROR &&
5494 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5495 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005498 /*
5499 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5500 * function, add the command to the end of the board's done queue.
5501 * The done function for the command will be called from
5502 * advansys_interrupt().
5503 */
5504 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005506 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507}
5508
5509/*
5510 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5511 *
5512 * Callback function for the Wide SCSI Adv Library.
5513 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005514static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005516 asc_board_t *boardp;
5517 adv_req_t *reqp;
5518 adv_sgblk_t *sgblkp;
5519 struct scsi_cmnd *scp;
5520 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005521 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005523 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5524 (ulong)adv_dvc_varp, (ulong)scsiqp);
5525 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005527 /*
5528 * Get the adv_req_t structure for the command that has been
5529 * completed. The adv_req_t structure actually contains the
5530 * completed ADV_SCSI_REQ_Q structure.
5531 */
5532 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5533 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5534 if (reqp == NULL) {
5535 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5536 return;
5537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005539 /*
5540 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5541 * command that has been completed.
5542 *
5543 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5544 * if any, are dropped, because a board structure pointer can not be
5545 * determined.
5546 */
5547 scp = reqp->cmndp;
5548 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5549 if (scp == NULL) {
5550 ASC_PRINT
5551 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5552 return;
5553 }
5554 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005556 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005557 ASC_STATS(shost, callback);
5558 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005560 /*
5561 * If the request isn't found on the active queue, it may have been
5562 * removed to handle a reset request. Display a message and return.
5563 *
5564 * Note: Because the structure may still be in use don't attempt
5565 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5566 */
5567 boardp = ASC_BOARDP(shost);
5568 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5569 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5570 ASC_PRINT2
5571 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5572 boardp->id, (ulong)scp);
5573 return;
5574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005576 /*
5577 * 'done_status' contains the command's ending status.
5578 */
5579 switch (scsiqp->done_status) {
5580 case QD_NO_ERROR:
5581 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5582 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005584 /*
5585 * Check for an underrun condition.
5586 *
5587 * If there was no error and an underrun condition, then
5588 * then return the number of underrun bytes.
5589 */
5590 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5591 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5592 resid_cnt <= scp->request_bufflen) {
5593 ASC_DBG1(1,
5594 "adv_isr_callback: underrun condition %lu bytes\n",
5595 (ulong)resid_cnt);
5596 scp->resid = resid_cnt;
5597 }
5598 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005600 case QD_WITH_ERROR:
5601 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5602 switch (scsiqp->host_status) {
5603 case QHSTA_NO_ERROR:
5604 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5605 ASC_DBG(2,
5606 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5607 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5608 sizeof(scp->sense_buffer));
5609 /*
5610 * Note: The 'status_byte()' macro used by target drivers
5611 * defined in scsi.h shifts the status byte returned by
5612 * host drivers right by 1 bit. This is why target drivers
5613 * also use right shifted status byte definitions. For
5614 * instance target drivers use CHECK_CONDITION, defined to
5615 * 0x1, instead of the SCSI defined check condition value
5616 * of 0x2. Host drivers are supposed to return the status
5617 * byte as it is defined by SCSI.
5618 */
5619 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5620 STATUS_BYTE(scsiqp->scsi_status);
5621 } else {
5622 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5623 }
5624 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005626 default:
5627 /* Some other QHSTA error occurred. */
5628 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5629 scsiqp->host_status);
5630 scp->result = HOST_BYTE(DID_BAD_TARGET);
5631 break;
5632 }
5633 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005635 case QD_ABORTED_BY_HOST:
5636 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5637 scp->result =
5638 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5639 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005641 default:
5642 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5643 scsiqp->done_status);
5644 scp->result =
5645 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5646 break;
5647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005649 /*
5650 * If the 'init_tidmask' bit isn't already set for the target and the
5651 * current request finished normally, then set the bit for the target
5652 * to indicate that a device is present.
5653 */
5654 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5655 scsiqp->done_status == QD_NO_ERROR &&
5656 scsiqp->host_status == QHSTA_NO_ERROR) {
5657 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005660 /*
5661 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5662 * function, add the command to the end of the board's done queue.
5663 * The done function for the command will be called from
5664 * advansys_interrupt().
5665 */
5666 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005668 /*
5669 * Free all 'adv_sgblk_t' structures allocated for the request.
5670 */
5671 while ((sgblkp = reqp->sgblkp) != NULL) {
5672 /* Remove 'sgblkp' from the request list. */
5673 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005675 /* Add 'sgblkp' to the board free list. */
5676 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5677 boardp->adv_sgblkp = sgblkp;
5678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005680 /*
5681 * Free the adv_req_t structure used with the command by adding
5682 * it back to the board free list.
5683 */
5684 reqp->next_reqp = boardp->adv_reqp;
5685 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005687 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005689 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690}
5691
5692/*
5693 * adv_async_callback() - Adv Library asynchronous event callback function.
5694 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005695static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005697 switch (code) {
5698 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5699 /*
5700 * The firmware detected a SCSI Bus reset.
5701 */
5702 ASC_DBG(0,
5703 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5704 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005705
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005706 case ADV_ASYNC_RDMA_FAILURE:
5707 /*
5708 * Handle RDMA failure by resetting the SCSI Bus and
5709 * possibly the chip if it is unresponsive. Log the error
5710 * with a unique code.
5711 */
5712 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5713 AdvResetChipAndSB(adv_dvc_varp);
5714 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005715
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005716 case ADV_HOST_SCSI_BUS_RESET:
5717 /*
5718 * Host generated SCSI bus reset occurred.
5719 */
5720 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5721 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005722
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005723 default:
5724 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5725 break;
5726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727}
5728
5729/*
5730 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5731 * to indicate a command is queued for the device.
5732 *
5733 * 'flag' may be either ASC_FRONT or ASC_BACK.
5734 *
5735 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5736 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005737static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005739 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005740
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005741 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5742 (ulong)ascq, (ulong)reqp, flag);
5743 ASC_ASSERT(reqp != NULL);
5744 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5745 tid = REQPTID(reqp);
5746 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5747 if (flag == ASC_FRONT) {
5748 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5749 ascq->q_first[tid] = reqp;
5750 /* If the queue was empty, set the last pointer. */
5751 if (ascq->q_last[tid] == NULL) {
5752 ascq->q_last[tid] = reqp;
5753 }
5754 } else { /* ASC_BACK */
5755 if (ascq->q_last[tid] != NULL) {
5756 ascq->q_last[tid]->host_scribble =
5757 (unsigned char *)reqp;
5758 }
5759 ascq->q_last[tid] = reqp;
5760 reqp->host_scribble = NULL;
5761 /* If the queue was empty, set the first pointer. */
5762 if (ascq->q_first[tid] == NULL) {
5763 ascq->q_first[tid] = reqp;
5764 }
5765 }
5766 /* The queue has at least one entry, set its bit. */
5767 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005769 /* Maintain request queue statistics. */
5770 ascq->q_tot_cnt[tid]++;
5771 ascq->q_cur_cnt[tid]++;
5772 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5773 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5774 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5775 tid, ascq->q_max_cnt[tid]);
5776 }
5777 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005779 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5780 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005781}
5782
5783/*
5784 * Return first queued 'REQP' on the specified queue for
5785 * the specified target device. Clear the 'tidmask' bit for
5786 * the device if no more commands are left queued for it.
5787 *
5788 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5789 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005790static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005792 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005793
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005794 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5795 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5796 if ((reqp = ascq->q_first[tid]) != NULL) {
5797 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5798 ascq->q_first[tid] = REQPNEXT(reqp);
5799 /* If the queue is empty, clear its bit and the last pointer. */
5800 if (ascq->q_first[tid] == NULL) {
5801 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5802 ASC_ASSERT(ascq->q_last[tid] == reqp);
5803 ascq->q_last[tid] = NULL;
5804 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005806 /* Maintain request queue statistics. */
5807 ascq->q_cur_cnt[tid]--;
5808 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
5809 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005811 }
5812 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
5813 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005814}
5815
5816/*
5817 * Return a pointer to a singly linked list of all the requests queued
5818 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
5819 *
5820 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
5821 * the last request returned in the singly linked list.
5822 *
5823 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
5824 * then all queued requests are concatenated into one list and
5825 * returned.
5826 *
5827 * Note: If 'lastpp' is used to append a new list to the end of
5828 * an old list, only change the old list last pointer if '*lastpp'
5829 * (or the function return value) is not NULL, i.e. use a temporary
5830 * variable for 'lastpp' and check its value after the function return
5831 * before assigning it to the list last pointer.
5832 *
5833 * Unfortunately collecting queuing time statistics adds overhead to
5834 * the function that isn't inherent to the function's algorithm.
5835 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005836static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005837{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005838 REQP firstp, lastp;
5839 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005841 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5842 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005844 /*
5845 * If 'tid' is not ASC_TID_ALL, return requests only for
5846 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
5847 * requests for all tids.
5848 */
5849 if (tid != ASC_TID_ALL) {
5850 /* Return all requests for the specified 'tid'. */
5851 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
5852 /* List is empty; Set first and last return pointers to NULL. */
5853 firstp = lastp = NULL;
5854 } else {
5855 firstp = ascq->q_first[tid];
5856 lastp = ascq->q_last[tid];
5857 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
5858 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005860 {
5861 REQP reqp;
5862 ascq->q_cur_cnt[tid] = 0;
5863 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5864 REQTIMESTAT("asc_dequeue_list", ascq,
5865 reqp, tid);
5866 }
5867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005869 }
5870 } else {
5871 /* Return all requests for all tids. */
5872 firstp = lastp = NULL;
5873 for (i = 0; i <= ADV_MAX_TID; i++) {
5874 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
5875 if (firstp == NULL) {
5876 firstp = ascq->q_first[i];
5877 lastp = ascq->q_last[i];
5878 } else {
5879 ASC_ASSERT(lastp != NULL);
5880 lastp->host_scribble =
5881 (unsigned char *)ascq->q_first[i];
5882 lastp = ascq->q_last[i];
5883 }
5884 ascq->q_first[i] = ascq->q_last[i] = NULL;
5885 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005887 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005889 }
5890 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005892 {
5893 REQP reqp;
5894 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5895 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
5896 reqp->device->id);
5897 }
5898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005900 }
5901 if (lastpp) {
5902 *lastpp = lastp;
5903 }
5904 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
5905 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906}
5907
5908/*
5909 * Remove the specified 'REQP' from the specified queue for
5910 * the specified target device. Clear the 'tidmask' bit for the
5911 * device if no more commands are left queued for it.
5912 *
5913 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
5914 *
5915 * Return ASC_TRUE if the command was found and removed,
5916 * otherwise return ASC_FALSE.
5917 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005918static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005920 REQP currp, prevp;
5921 int tid;
5922 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005924 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
5925 (ulong)ascq, (ulong)reqp);
5926 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005928 tid = REQPTID(reqp);
5929 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005931 /*
5932 * Handle the common case of 'reqp' being the first
5933 * entry on the queue.
5934 */
5935 if (reqp == ascq->q_first[tid]) {
5936 ret = ASC_TRUE;
5937 ascq->q_first[tid] = REQPNEXT(reqp);
5938 /* If the queue is now empty, clear its bit and the last pointer. */
5939 if (ascq->q_first[tid] == NULL) {
5940 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5941 ASC_ASSERT(ascq->q_last[tid] == reqp);
5942 ascq->q_last[tid] = NULL;
5943 }
5944 } else if (ascq->q_first[tid] != NULL) {
5945 ASC_ASSERT(ascq->q_last[tid] != NULL);
5946 /*
5947 * Because the case of 'reqp' being the first entry has been
5948 * handled above and it is known the queue is not empty, if
5949 * 'reqp' is found on the queue it is guaranteed the queue will
5950 * not become empty and that 'q_first[tid]' will not be changed.
5951 *
5952 * Set 'prevp' to the first entry, 'currp' to the second entry,
5953 * and search for 'reqp'.
5954 */
5955 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
5956 currp; prevp = currp, currp = REQPNEXT(currp)) {
5957 if (currp == reqp) {
5958 ret = ASC_TRUE;
5959 prevp->host_scribble =
5960 (unsigned char *)REQPNEXT(currp);
5961 reqp->host_scribble = NULL;
5962 if (ascq->q_last[tid] == reqp) {
5963 ascq->q_last[tid] = prevp;
5964 }
5965 break;
5966 }
5967 }
5968 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005970 /* Maintain request queue statistics. */
5971 if (ret == ASC_TRUE) {
5972 ascq->q_cur_cnt[tid]--;
5973 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
5974 }
5975 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005977 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
5978 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979}
5980
5981/*
5982 * Execute as many queued requests as possible for the specified queue.
5983 *
5984 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
5985 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005986static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005988 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
5989 REQP reqp;
5990 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005992 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
5993 /*
5994 * Execute queued commands for devices attached to
5995 * the current board in round-robin fashion.
5996 */
5997 scan_tidmask = ascq->q_tidmask;
5998 do {
5999 for (i = 0; i <= ADV_MAX_TID; i++) {
6000 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
6001 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
6002 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6003 } else
6004 if (asc_execute_scsi_cmnd
6005 ((struct scsi_cmnd *)reqp)
6006 == ASC_BUSY) {
6007 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6008 /*
6009 * The request returned ASC_BUSY. Enqueue at the front of
6010 * target's waiting list to maintain correct ordering.
6011 */
6012 asc_enqueue(ascq, reqp, ASC_FRONT);
6013 }
6014 }
6015 }
6016 } while (scan_tidmask);
6017 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018}
6019
6020#ifdef CONFIG_PROC_FS
6021/*
6022 * asc_prt_board_devices()
6023 *
6024 * Print driver information for devices attached to the board.
6025 *
6026 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6027 * cf. asc_prt_line().
6028 *
6029 * Return the number of characters copied into 'cp'. No more than
6030 * 'cplen' characters will be copied to 'cp'.
6031 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006032static int asc_prt_board_devices(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 int chip_scsi_id;
6039 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006041 boardp = ASC_BOARDP(shost);
6042 leftlen = cplen;
6043 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006045 len = asc_prt_line(cp, leftlen,
6046 "\nDevice Information for AdvanSys SCSI Host %d:\n",
6047 shost->host_no);
6048 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006050 if (ASC_NARROW_BOARD(boardp)) {
6051 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6052 } else {
6053 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006056 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6057 ASC_PRT_NEXT();
6058 for (i = 0; i <= ADV_MAX_TID; i++) {
6059 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6060 len = asc_prt_line(cp, leftlen, " %X,", i);
6061 ASC_PRT_NEXT();
6062 }
6063 }
6064 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6065 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006067 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006068}
6069
6070/*
6071 * Display Wide Board BIOS Information.
6072 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006073static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006075 asc_board_t *boardp;
6076 int leftlen;
6077 int totlen;
6078 int len;
6079 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006081 boardp = ASC_BOARDP(shost);
6082 leftlen = cplen;
6083 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006085 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6086 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006087
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006088 /*
6089 * If the BIOS saved a valid signature, then fill in
6090 * the BIOS code segment base address.
6091 */
6092 if (boardp->bios_signature != 0x55AA) {
6093 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6094 ASC_PRT_NEXT();
6095 len = asc_prt_line(cp, leftlen,
6096 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6097 ASC_PRT_NEXT();
6098 len = asc_prt_line(cp, leftlen,
6099 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6100 ASC_PRT_NEXT();
6101 } else {
6102 major = (boardp->bios_version >> 12) & 0xF;
6103 minor = (boardp->bios_version >> 8) & 0xF;
6104 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006106 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6107 major, minor,
6108 letter >= 26 ? '?' : letter + 'A');
6109 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006110
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006111 /*
6112 * Current available ROM BIOS release is 3.1I for UW
6113 * and 3.2I for U2W. This code doesn't differentiate
6114 * UW and U2W boards.
6115 */
6116 if (major < 3 || (major <= 3 && minor < 1) ||
6117 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6118 len = asc_prt_line(cp, leftlen,
6119 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6120 ASC_PRT_NEXT();
6121 len = asc_prt_line(cp, leftlen,
6122 "ftp://ftp.connectcom.net/pub\n");
6123 ASC_PRT_NEXT();
6124 }
6125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006126
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006127 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128}
6129
6130/*
6131 * Add serial number to information bar if signature AAh
6132 * is found in at bit 15-9 (7 bits) of word 1.
6133 *
6134 * Serial Number consists fo 12 alpha-numeric digits.
6135 *
6136 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6137 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6138 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6139 * 5 - Product revision (A-J) Word0: " "
6140 *
6141 * Signature Word1: 15-9 (7 bits)
6142 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6143 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6144 *
6145 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6146 *
6147 * Note 1: Only production cards will have a serial number.
6148 *
6149 * Note 2: Signature is most significant 7 bits (0xFE).
6150 *
6151 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6152 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006153static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006154{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006155 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006157 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6158 return ASC_FALSE;
6159 } else {
6160 /*
6161 * First word - 6 digits.
6162 */
6163 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006164
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006165 /* Product type - 1st digit. */
6166 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6167 /* Product type is P=Prototype */
6168 *cp += 0x8;
6169 }
6170 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006172 /* Manufacturing location - 2nd digit. */
6173 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006174
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006175 /* Product ID - 3rd, 4th digits. */
6176 num = w & 0x3FF;
6177 *cp++ = '0' + (num / 100);
6178 num %= 100;
6179 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006181 /* Product revision - 5th digit. */
6182 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006184 /*
6185 * Second word
6186 */
6187 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006188
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006189 /*
6190 * Year - 6th digit.
6191 *
6192 * If bit 15 of third word is set, then the
6193 * last digit of the year is greater than 7.
6194 */
6195 if (serialnum[2] & 0x8000) {
6196 *cp++ = '8' + ((w & 0x1C0) >> 6);
6197 } else {
6198 *cp++ = '0' + ((w & 0x1C0) >> 6);
6199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006201 /* Week of year - 7th, 8th digits. */
6202 num = w & 0x003F;
6203 *cp++ = '0' + num / 10;
6204 num %= 10;
6205 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006207 /*
6208 * Third word
6209 */
6210 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006212 /* Serial number - 9th digit. */
6213 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006215 /* 10th, 11th, 12th digits. */
6216 num = w % 1000;
6217 *cp++ = '0' + num / 100;
6218 num %= 100;
6219 *cp++ = '0' + num / 10;
6220 num %= 10;
6221 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006223 *cp = '\0'; /* Null Terminate the string. */
6224 return ASC_TRUE;
6225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226}
6227
6228/*
6229 * asc_prt_asc_board_eeprom()
6230 *
6231 * Print board EEPROM configuration.
6232 *
6233 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6234 * cf. asc_prt_line().
6235 *
6236 * Return the number of characters copied into 'cp'. No more than
6237 * 'cplen' characters will be copied to 'cp'.
6238 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006239static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006240{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006241 asc_board_t *boardp;
6242 ASC_DVC_VAR *asc_dvc_varp;
6243 int leftlen;
6244 int totlen;
6245 int len;
6246 ASCEEP_CONFIG *ep;
6247 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006249 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006251 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006253 boardp = ASC_BOARDP(shost);
6254 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6255 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006257 leftlen = cplen;
6258 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006260 len = asc_prt_line(cp, leftlen,
6261 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6262 shost->host_no);
6263 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006265 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6266 == ASC_TRUE) {
6267 len =
6268 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6269 serialstr);
6270 ASC_PRT_NEXT();
6271 } else {
6272 if (ep->adapter_info[5] == 0xBB) {
6273 len = asc_prt_line(cp, leftlen,
6274 " Default Settings Used for EEPROM-less Adapter.\n");
6275 ASC_PRT_NEXT();
6276 } else {
6277 len = asc_prt_line(cp, leftlen,
6278 " Serial Number Signature Not Present.\n");
6279 ASC_PRT_NEXT();
6280 }
6281 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006282
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006283 len = asc_prt_line(cp, leftlen,
6284 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6285 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6286 ep->max_tag_qng);
6287 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006288
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006289 len = asc_prt_line(cp, leftlen,
6290 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6291 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006293 len = asc_prt_line(cp, leftlen, " Target ID: ");
6294 ASC_PRT_NEXT();
6295 for (i = 0; i <= ASC_MAX_TID; i++) {
6296 len = asc_prt_line(cp, leftlen, " %d", i);
6297 ASC_PRT_NEXT();
6298 }
6299 len = asc_prt_line(cp, leftlen, "\n");
6300 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006302 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6303 ASC_PRT_NEXT();
6304 for (i = 0; i <= ASC_MAX_TID; i++) {
6305 len = asc_prt_line(cp, leftlen, " %c",
6306 (ep->
6307 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6308 'N');
6309 ASC_PRT_NEXT();
6310 }
6311 len = asc_prt_line(cp, leftlen, "\n");
6312 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006313
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006314 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6315 ASC_PRT_NEXT();
6316 for (i = 0; i <= ASC_MAX_TID; i++) {
6317 len = asc_prt_line(cp, leftlen, " %c",
6318 (ep->
6319 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6320 'N');
6321 ASC_PRT_NEXT();
6322 }
6323 len = asc_prt_line(cp, leftlen, "\n");
6324 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006325
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006326 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6327 ASC_PRT_NEXT();
6328 for (i = 0; i <= ASC_MAX_TID; i++) {
6329 len = asc_prt_line(cp, leftlen, " %c",
6330 (ep->
6331 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6332 'N');
6333 ASC_PRT_NEXT();
6334 }
6335 len = asc_prt_line(cp, leftlen, "\n");
6336 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006337
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006338 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6339 ASC_PRT_NEXT();
6340 for (i = 0; i <= ASC_MAX_TID; i++) {
6341 len = asc_prt_line(cp, leftlen, " %c",
6342 (ep->
6343 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6344 'N');
6345 ASC_PRT_NEXT();
6346 }
6347 len = asc_prt_line(cp, leftlen, "\n");
6348 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349
6350#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006351 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6352 len = asc_prt_line(cp, leftlen,
6353 " Host ISA DMA speed: %d MB/S\n",
6354 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6355 ASC_PRT_NEXT();
6356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006357#endif /* CONFIG_ISA */
6358
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006359 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006360}
6361
6362/*
6363 * asc_prt_adv_board_eeprom()
6364 *
6365 * Print board EEPROM configuration.
6366 *
6367 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6368 * cf. asc_prt_line().
6369 *
6370 * Return the number of characters copied into 'cp'. No more than
6371 * 'cplen' characters will be copied to 'cp'.
6372 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006373static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006375 asc_board_t *boardp;
6376 ADV_DVC_VAR *adv_dvc_varp;
6377 int leftlen;
6378 int totlen;
6379 int len;
6380 int i;
6381 char *termstr;
6382 uchar serialstr[13];
6383 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6384 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6385 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6386 ushort word;
6387 ushort *wordp;
6388 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006390 boardp = ASC_BOARDP(shost);
6391 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6392 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6393 ep_3550 = &boardp->eep_config.adv_3550_eep;
6394 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6395 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6396 } else {
6397 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006400 leftlen = cplen;
6401 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006403 len = asc_prt_line(cp, leftlen,
6404 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6405 shost->host_no);
6406 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006407
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006408 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6409 wordp = &ep_3550->serial_number_word1;
6410 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6411 wordp = &ep_38C0800->serial_number_word1;
6412 } else {
6413 wordp = &ep_38C1600->serial_number_word1;
6414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006415
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006416 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6417 len =
6418 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6419 serialstr);
6420 ASC_PRT_NEXT();
6421 } else {
6422 len = asc_prt_line(cp, leftlen,
6423 " Serial Number Signature Not Present.\n");
6424 ASC_PRT_NEXT();
6425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006426
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006427 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6428 len = asc_prt_line(cp, leftlen,
6429 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6430 ep_3550->adapter_scsi_id,
6431 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6432 ASC_PRT_NEXT();
6433 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6434 len = asc_prt_line(cp, leftlen,
6435 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6436 ep_38C0800->adapter_scsi_id,
6437 ep_38C0800->max_host_qng,
6438 ep_38C0800->max_dvc_qng);
6439 ASC_PRT_NEXT();
6440 } else {
6441 len = asc_prt_line(cp, leftlen,
6442 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6443 ep_38C1600->adapter_scsi_id,
6444 ep_38C1600->max_host_qng,
6445 ep_38C1600->max_dvc_qng);
6446 ASC_PRT_NEXT();
6447 }
6448 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6449 word = ep_3550->termination;
6450 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6451 word = ep_38C0800->termination_lvd;
6452 } else {
6453 word = ep_38C1600->termination_lvd;
6454 }
6455 switch (word) {
6456 case 1:
6457 termstr = "Low Off/High Off";
6458 break;
6459 case 2:
6460 termstr = "Low Off/High On";
6461 break;
6462 case 3:
6463 termstr = "Low On/High On";
6464 break;
6465 default:
6466 case 0:
6467 termstr = "Automatic";
6468 break;
6469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006470
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006471 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6472 len = asc_prt_line(cp, leftlen,
6473 " termination: %u (%s), bios_ctrl: 0x%x\n",
6474 ep_3550->termination, termstr,
6475 ep_3550->bios_ctrl);
6476 ASC_PRT_NEXT();
6477 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6478 len = asc_prt_line(cp, leftlen,
6479 " termination: %u (%s), bios_ctrl: 0x%x\n",
6480 ep_38C0800->termination_lvd, termstr,
6481 ep_38C0800->bios_ctrl);
6482 ASC_PRT_NEXT();
6483 } else {
6484 len = asc_prt_line(cp, leftlen,
6485 " termination: %u (%s), bios_ctrl: 0x%x\n",
6486 ep_38C1600->termination_lvd, termstr,
6487 ep_38C1600->bios_ctrl);
6488 ASC_PRT_NEXT();
6489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006490
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006491 len = asc_prt_line(cp, leftlen, " Target ID: ");
6492 ASC_PRT_NEXT();
6493 for (i = 0; i <= ADV_MAX_TID; i++) {
6494 len = asc_prt_line(cp, leftlen, " %X", i);
6495 ASC_PRT_NEXT();
6496 }
6497 len = asc_prt_line(cp, leftlen, "\n");
6498 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006499
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006500 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6501 word = ep_3550->disc_enable;
6502 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6503 word = ep_38C0800->disc_enable;
6504 } else {
6505 word = ep_38C1600->disc_enable;
6506 }
6507 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6508 ASC_PRT_NEXT();
6509 for (i = 0; i <= ADV_MAX_TID; i++) {
6510 len = asc_prt_line(cp, leftlen, " %c",
6511 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6512 ASC_PRT_NEXT();
6513 }
6514 len = asc_prt_line(cp, leftlen, "\n");
6515 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006517 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6518 word = ep_3550->tagqng_able;
6519 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6520 word = ep_38C0800->tagqng_able;
6521 } else {
6522 word = ep_38C1600->tagqng_able;
6523 }
6524 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6525 ASC_PRT_NEXT();
6526 for (i = 0; i <= ADV_MAX_TID; i++) {
6527 len = asc_prt_line(cp, leftlen, " %c",
6528 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6529 ASC_PRT_NEXT();
6530 }
6531 len = asc_prt_line(cp, leftlen, "\n");
6532 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006533
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006534 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6535 word = ep_3550->start_motor;
6536 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6537 word = ep_38C0800->start_motor;
6538 } else {
6539 word = ep_38C1600->start_motor;
6540 }
6541 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6542 ASC_PRT_NEXT();
6543 for (i = 0; i <= ADV_MAX_TID; i++) {
6544 len = asc_prt_line(cp, leftlen, " %c",
6545 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6546 ASC_PRT_NEXT();
6547 }
6548 len = asc_prt_line(cp, leftlen, "\n");
6549 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006551 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6552 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6553 ASC_PRT_NEXT();
6554 for (i = 0; i <= ADV_MAX_TID; i++) {
6555 len = asc_prt_line(cp, leftlen, " %c",
6556 (ep_3550->
6557 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6558 'Y' : 'N');
6559 ASC_PRT_NEXT();
6560 }
6561 len = asc_prt_line(cp, leftlen, "\n");
6562 ASC_PRT_NEXT();
6563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006564
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006565 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6566 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6567 ASC_PRT_NEXT();
6568 for (i = 0; i <= ADV_MAX_TID; i++) {
6569 len = asc_prt_line(cp, leftlen, " %c",
6570 (ep_3550->
6571 ultra_able & ADV_TID_TO_TIDMASK(i))
6572 ? 'Y' : 'N');
6573 ASC_PRT_NEXT();
6574 }
6575 len = asc_prt_line(cp, leftlen, "\n");
6576 ASC_PRT_NEXT();
6577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006578
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006579 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6580 word = ep_3550->wdtr_able;
6581 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6582 word = ep_38C0800->wdtr_able;
6583 } else {
6584 word = ep_38C1600->wdtr_able;
6585 }
6586 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6587 ASC_PRT_NEXT();
6588 for (i = 0; i <= ADV_MAX_TID; i++) {
6589 len = asc_prt_line(cp, leftlen, " %c",
6590 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6591 ASC_PRT_NEXT();
6592 }
6593 len = asc_prt_line(cp, leftlen, "\n");
6594 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006595
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006596 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6597 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6598 len = asc_prt_line(cp, leftlen,
6599 " Synchronous Transfer Speed (Mhz):\n ");
6600 ASC_PRT_NEXT();
6601 for (i = 0; i <= ADV_MAX_TID; i++) {
6602 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006604 if (i == 0) {
6605 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6606 } else if (i == 4) {
6607 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6608 } else if (i == 8) {
6609 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6610 } else if (i == 12) {
6611 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6612 }
6613 switch (sdtr_speed & ADV_MAX_TID) {
6614 case 0:
6615 speed_str = "Off";
6616 break;
6617 case 1:
6618 speed_str = " 5";
6619 break;
6620 case 2:
6621 speed_str = " 10";
6622 break;
6623 case 3:
6624 speed_str = " 20";
6625 break;
6626 case 4:
6627 speed_str = " 40";
6628 break;
6629 case 5:
6630 speed_str = " 80";
6631 break;
6632 default:
6633 speed_str = "Unk";
6634 break;
6635 }
6636 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6637 ASC_PRT_NEXT();
6638 if (i == 7) {
6639 len = asc_prt_line(cp, leftlen, "\n ");
6640 ASC_PRT_NEXT();
6641 }
6642 sdtr_speed >>= 4;
6643 }
6644 len = asc_prt_line(cp, leftlen, "\n");
6645 ASC_PRT_NEXT();
6646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006647
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006648 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006649}
6650
6651/*
6652 * asc_prt_driver_conf()
6653 *
6654 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6655 * cf. asc_prt_line().
6656 *
6657 * Return the number of characters copied into 'cp'. No more than
6658 * 'cplen' characters will be copied to 'cp'.
6659 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006660static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006661{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006662 asc_board_t *boardp;
6663 int leftlen;
6664 int totlen;
6665 int len;
6666 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006668 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006670 leftlen = cplen;
6671 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006672
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006673 len = asc_prt_line(cp, leftlen,
6674 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6675 shost->host_no);
6676 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006677
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006678 len = asc_prt_line(cp, leftlen,
6679 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6680 shost->host_busy, shost->last_reset, shost->max_id,
6681 shost->max_lun, shost->max_channel);
6682 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006683
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006684 len = asc_prt_line(cp, leftlen,
6685 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6686 shost->unique_id, shost->can_queue, shost->this_id,
6687 shost->sg_tablesize, shost->cmd_per_lun);
6688 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006689
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006690 len = asc_prt_line(cp, leftlen,
6691 " unchecked_isa_dma %d, use_clustering %d\n",
6692 shost->unchecked_isa_dma, shost->use_clustering);
6693 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006694
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006695 len = asc_prt_line(cp, leftlen,
6696 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6697 boardp->flags, boardp->last_reset, jiffies,
6698 boardp->asc_n_io_port);
6699 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006700
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006701 /* 'shost->n_io_port' may be truncated because it is only one byte. */
6702 len = asc_prt_line(cp, leftlen,
6703 " io_port 0x%x, n_io_port 0x%x\n",
6704 shost->io_port, shost->n_io_port);
6705 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006706
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006707 if (ASC_NARROW_BOARD(boardp)) {
6708 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6709 } else {
6710 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6711 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006712
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006713 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006714}
6715
6716/*
6717 * asc_prt_asc_board_info()
6718 *
6719 * Print dynamic board configuration information.
6720 *
6721 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6722 * cf. asc_prt_line().
6723 *
6724 * Return the number of characters copied into 'cp'. No more than
6725 * 'cplen' characters will be copied to 'cp'.
6726 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006727static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006728{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006729 asc_board_t *boardp;
6730 int chip_scsi_id;
6731 int leftlen;
6732 int totlen;
6733 int len;
6734 ASC_DVC_VAR *v;
6735 ASC_DVC_CFG *c;
6736 int i;
6737 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006738
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006739 boardp = ASC_BOARDP(shost);
6740 v = &boardp->dvc_var.asc_dvc_var;
6741 c = &boardp->dvc_cfg.asc_dvc_cfg;
6742 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006743
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006744 leftlen = cplen;
6745 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006746
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006747 len = asc_prt_line(cp, leftlen,
6748 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6749 shost->host_no);
6750 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006751
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006752 len = asc_prt_line(cp, leftlen,
6753 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6754 c->chip_version, c->lib_version, c->lib_serial_no,
6755 c->mcode_date);
6756 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006757
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006758 len = asc_prt_line(cp, leftlen,
6759 " mcode_version 0x%x, err_code %u\n",
6760 c->mcode_version, v->err_code);
6761 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006763 /* Current number of commands waiting for the host. */
6764 len = asc_prt_line(cp, leftlen,
6765 " Total Command Pending: %d\n", v->cur_total_qng);
6766 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006767
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006768 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6769 ASC_PRT_NEXT();
6770 for (i = 0; i <= ASC_MAX_TID; i++) {
6771 if ((chip_scsi_id == i) ||
6772 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6773 continue;
6774 }
6775 len = asc_prt_line(cp, leftlen, " %X:%c",
6776 i,
6777 (v->
6778 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6779 'Y' : 'N');
6780 ASC_PRT_NEXT();
6781 }
6782 len = asc_prt_line(cp, leftlen, "\n");
6783 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006784
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006785 /* Current number of commands waiting for a device. */
6786 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6787 ASC_PRT_NEXT();
6788 for (i = 0; i <= ASC_MAX_TID; i++) {
6789 if ((chip_scsi_id == i) ||
6790 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6791 continue;
6792 }
6793 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6794 ASC_PRT_NEXT();
6795 }
6796 len = asc_prt_line(cp, leftlen, "\n");
6797 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006798
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006799 /* Current limit on number of commands that can be sent to a device. */
6800 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6801 ASC_PRT_NEXT();
6802 for (i = 0; i <= ASC_MAX_TID; i++) {
6803 if ((chip_scsi_id == i) ||
6804 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6805 continue;
6806 }
6807 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
6808 ASC_PRT_NEXT();
6809 }
6810 len = asc_prt_line(cp, leftlen, "\n");
6811 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006812
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006813 /* Indicate whether the device has returned queue full status. */
6814 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
6815 ASC_PRT_NEXT();
6816 for (i = 0; i <= ASC_MAX_TID; i++) {
6817 if ((chip_scsi_id == i) ||
6818 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6819 continue;
6820 }
6821 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
6822 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
6823 i, boardp->queue_full_cnt[i]);
6824 } else {
6825 len = asc_prt_line(cp, leftlen, " %X:N", i);
6826 }
6827 ASC_PRT_NEXT();
6828 }
6829 len = asc_prt_line(cp, leftlen, "\n");
6830 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006832 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6833 ASC_PRT_NEXT();
6834 for (i = 0; i <= ASC_MAX_TID; i++) {
6835 if ((chip_scsi_id == i) ||
6836 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6837 continue;
6838 }
6839 len = asc_prt_line(cp, leftlen, " %X:%c",
6840 i,
6841 (v->
6842 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6843 'N');
6844 ASC_PRT_NEXT();
6845 }
6846 len = asc_prt_line(cp, leftlen, "\n");
6847 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006848
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006849 for (i = 0; i <= ASC_MAX_TID; i++) {
6850 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006851
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006852 if ((chip_scsi_id == i) ||
6853 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6854 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
6855 continue;
6856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006857
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006858 len = asc_prt_line(cp, leftlen, " %X:", i);
6859 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006860
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006861 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
6862 len = asc_prt_line(cp, leftlen, " Asynchronous");
6863 ASC_PRT_NEXT();
6864 } else {
6865 syn_period_ix =
6866 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
6867 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006868
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006869 len = asc_prt_line(cp, leftlen,
6870 " Transfer Period Factor: %d (%d.%d Mhz),",
6871 v->sdtr_period_tbl[syn_period_ix],
6872 250 /
6873 v->sdtr_period_tbl[syn_period_ix],
6874 ASC_TENTHS(250,
6875 v->
6876 sdtr_period_tbl
6877 [syn_period_ix]));
6878 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006879
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006880 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6881 boardp->
6882 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
6883 ASC_PRT_NEXT();
6884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006885
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006886 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6887 len = asc_prt_line(cp, leftlen, "*\n");
6888 renegotiate = 1;
6889 } else {
6890 len = asc_prt_line(cp, leftlen, "\n");
6891 }
6892 ASC_PRT_NEXT();
6893 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006894
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006895 if (renegotiate) {
6896 len = asc_prt_line(cp, leftlen,
6897 " * = Re-negotiation pending before next command.\n");
6898 ASC_PRT_NEXT();
6899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006900
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006901 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006902}
6903
6904/*
6905 * asc_prt_adv_board_info()
6906 *
6907 * Print dynamic board configuration information.
6908 *
6909 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6910 * cf. asc_prt_line().
6911 *
6912 * Return the number of characters copied into 'cp'. No more than
6913 * 'cplen' characters will be copied to 'cp'.
6914 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006915static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006916{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006917 asc_board_t *boardp;
6918 int leftlen;
6919 int totlen;
6920 int len;
6921 int i;
6922 ADV_DVC_VAR *v;
6923 ADV_DVC_CFG *c;
6924 AdvPortAddr iop_base;
6925 ushort chip_scsi_id;
6926 ushort lramword;
6927 uchar lrambyte;
6928 ushort tagqng_able;
6929 ushort sdtr_able, wdtr_able;
6930 ushort wdtr_done, sdtr_done;
6931 ushort period = 0;
6932 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006933
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006934 boardp = ASC_BOARDP(shost);
6935 v = &boardp->dvc_var.adv_dvc_var;
6936 c = &boardp->dvc_cfg.adv_dvc_cfg;
6937 iop_base = v->iop_base;
6938 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006939
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006940 leftlen = cplen;
6941 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006942
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006943 len = asc_prt_line(cp, leftlen,
6944 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6945 shost->host_no);
6946 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006947
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006948 len = asc_prt_line(cp, leftlen,
6949 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
6950 v->iop_base,
6951 AdvReadWordRegister(iop_base,
6952 IOPW_SCSI_CFG1) & CABLE_DETECT,
6953 v->err_code);
6954 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006955
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006956 len = asc_prt_line(cp, leftlen,
6957 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
6958 c->chip_version, c->lib_version, c->mcode_date,
6959 c->mcode_version);
6960 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006961
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006962 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
6963 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
6964 ASC_PRT_NEXT();
6965 for (i = 0; i <= ADV_MAX_TID; i++) {
6966 if ((chip_scsi_id == i) ||
6967 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6968 continue;
6969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006970
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006971 len = asc_prt_line(cp, leftlen, " %X:%c",
6972 i,
6973 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6974 'N');
6975 ASC_PRT_NEXT();
6976 }
6977 len = asc_prt_line(cp, leftlen, "\n");
6978 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006979
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006980 len = asc_prt_line(cp, leftlen, " Queue Limit:");
6981 ASC_PRT_NEXT();
6982 for (i = 0; i <= ADV_MAX_TID; i++) {
6983 if ((chip_scsi_id == i) ||
6984 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6985 continue;
6986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006987
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006988 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
6989 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006990
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006991 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6992 ASC_PRT_NEXT();
6993 }
6994 len = asc_prt_line(cp, leftlen, "\n");
6995 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006996
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006997 len = asc_prt_line(cp, leftlen, " Command Pending:");
6998 ASC_PRT_NEXT();
6999 for (i = 0; i <= ADV_MAX_TID; i++) {
7000 if ((chip_scsi_id == i) ||
7001 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7002 continue;
7003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007004
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007005 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
7006 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007007
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007008 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
7009 ASC_PRT_NEXT();
7010 }
7011 len = asc_prt_line(cp, leftlen, "\n");
7012 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007013
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007014 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
7015 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
7016 ASC_PRT_NEXT();
7017 for (i = 0; i <= ADV_MAX_TID; i++) {
7018 if ((chip_scsi_id == i) ||
7019 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7020 continue;
7021 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007022
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007023 len = asc_prt_line(cp, leftlen, " %X:%c",
7024 i,
7025 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7026 'N');
7027 ASC_PRT_NEXT();
7028 }
7029 len = asc_prt_line(cp, leftlen, "\n");
7030 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007031
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007032 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
7033 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
7034 ASC_PRT_NEXT();
7035 for (i = 0; i <= ADV_MAX_TID; i++) {
7036 if ((chip_scsi_id == i) ||
7037 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7038 continue;
7039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007040
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007041 AdvReadWordLram(iop_base,
7042 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7043 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007044
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007045 len = asc_prt_line(cp, leftlen, " %X:%d",
7046 i, (lramword & 0x8000) ? 16 : 8);
7047 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007048
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007049 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
7050 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7051 len = asc_prt_line(cp, leftlen, "*");
7052 ASC_PRT_NEXT();
7053 renegotiate = 1;
7054 }
7055 }
7056 len = asc_prt_line(cp, leftlen, "\n");
7057 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007058
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007059 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7060 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7061 ASC_PRT_NEXT();
7062 for (i = 0; i <= ADV_MAX_TID; i++) {
7063 if ((chip_scsi_id == i) ||
7064 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7065 continue;
7066 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007067
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007068 len = asc_prt_line(cp, leftlen, " %X:%c",
7069 i,
7070 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7071 'N');
7072 ASC_PRT_NEXT();
7073 }
7074 len = asc_prt_line(cp, leftlen, "\n");
7075 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007076
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007077 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7078 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007080 AdvReadWordLram(iop_base,
7081 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7082 lramword);
7083 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007084
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007085 if ((chip_scsi_id == i) ||
7086 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7087 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7088 continue;
7089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007090
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007091 len = asc_prt_line(cp, leftlen, " %X:", i);
7092 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007093
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007094 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7095 len = asc_prt_line(cp, leftlen, " Asynchronous");
7096 ASC_PRT_NEXT();
7097 } else {
7098 len =
7099 asc_prt_line(cp, leftlen,
7100 " Transfer Period Factor: ");
7101 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007102
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007103 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7104 len =
7105 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7106 ASC_PRT_NEXT();
7107 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7108 len =
7109 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7110 ASC_PRT_NEXT();
7111 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007113 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007114
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007115 if (period == 0) { /* Should never happen. */
7116 len =
7117 asc_prt_line(cp, leftlen,
7118 "%d (? Mhz), ");
7119 ASC_PRT_NEXT();
7120 } else {
7121 len = asc_prt_line(cp, leftlen,
7122 "%d (%d.%d Mhz),",
7123 period, 250 / period,
7124 ASC_TENTHS(250,
7125 period));
7126 ASC_PRT_NEXT();
7127 }
7128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007129
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007130 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7131 lramword & 0x1F);
7132 ASC_PRT_NEXT();
7133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007134
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007135 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7136 len = asc_prt_line(cp, leftlen, "*\n");
7137 renegotiate = 1;
7138 } else {
7139 len = asc_prt_line(cp, leftlen, "\n");
7140 }
7141 ASC_PRT_NEXT();
7142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007143
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007144 if (renegotiate) {
7145 len = asc_prt_line(cp, leftlen,
7146 " * = Re-negotiation pending before next command.\n");
7147 ASC_PRT_NEXT();
7148 }
7149
7150 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007151}
7152
7153/*
7154 * asc_proc_copy()
7155 *
7156 * Copy proc information to a read buffer taking into account the current
7157 * read offset in the file and the remaining space in the read buffer.
7158 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007159static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007160asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007161 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007162{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007163 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007164
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007165 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7166 (unsigned)offset, (unsigned)advoffset, cplen);
7167 if (offset <= advoffset) {
7168 /* Read offset below current offset, copy everything. */
7169 cnt = min(cplen, leftlen);
7170 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7171 (ulong)curbuf, (ulong)cp, cnt);
7172 memcpy(curbuf, cp, cnt);
7173 } else if (offset < advoffset + cplen) {
7174 /* Read offset within current range, partial copy. */
7175 cnt = (advoffset + cplen) - offset;
7176 cp = (cp + cplen) - cnt;
7177 cnt = min(cnt, leftlen);
7178 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7179 (ulong)curbuf, (ulong)cp, cnt);
7180 memcpy(curbuf, cp, cnt);
7181 }
7182 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007183}
7184
7185/*
7186 * asc_prt_line()
7187 *
7188 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7189 *
7190 * Return 0 if printing to the console, otherwise return the number of
7191 * bytes written to the buffer.
7192 *
7193 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7194 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7195 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007196static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007197{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007198 va_list args;
7199 int ret;
7200 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007201
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007202 va_start(args, fmt);
7203 ret = vsprintf(s, fmt, args);
7204 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7205 if (buf == NULL) {
7206 (void)printk(s);
7207 ret = 0;
7208 } else {
7209 ret = min(buflen, ret);
7210 memcpy(buf, s, ret);
7211 }
7212 va_end(args);
7213 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007214}
7215#endif /* CONFIG_PROC_FS */
7216
Linus Torvalds1da177e2005-04-16 15:20:36 -07007217/*
7218 * --- Functions Required by the Asc Library
7219 */
7220
7221/*
7222 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7223 * global variable which is incremented once every 5 ms
7224 * from a timer interrupt, because this function may be
7225 * called when interrupts are disabled.
7226 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007227static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007228{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007229 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7230 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007231}
7232
7233/*
7234 * Currently and inline noop but leave as a placeholder.
7235 * Leave DvcEnterCritical() as a noop placeholder.
7236 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007237static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007238{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007239 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007240}
7241
7242/*
7243 * Critical sections are all protected by the board spinlock.
7244 * Leave DvcLeaveCritical() as a noop placeholder.
7245 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007246static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007247{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007248 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007249}
7250
7251/*
7252 * void
7253 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7254 *
7255 * Calling/Exit State:
7256 * none
7257 *
7258 * Description:
7259 * Output an ASC_SCSI_Q structure to the chip
7260 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007261static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007262DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7263{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007264 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007265
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007266 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7267 AscSetChipLramAddr(iop_base, s_addr);
7268 for (i = 0; i < 2 * words; i += 2) {
7269 if (i == 4 || i == 20) {
7270 continue;
7271 }
7272 outpw(iop_base + IOP_RAM_DATA,
7273 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007275}
7276
7277/*
7278 * void
7279 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7280 *
7281 * Calling/Exit State:
7282 * none
7283 *
7284 * Description:
7285 * Input an ASC_QDONE_INFO structure from the chip
7286 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007287static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007288DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7289{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007290 int i;
7291 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007292
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007293 AscSetChipLramAddr(iop_base, s_addr);
7294 for (i = 0; i < 2 * words; i += 2) {
7295 if (i == 10) {
7296 continue;
7297 }
7298 word = inpw(iop_base + IOP_RAM_DATA);
7299 inbuf[i] = word & 0xff;
7300 inbuf[i + 1] = (word >> 8) & 0xff;
7301 }
7302 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007303}
7304
7305/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007306 * Return the BIOS address of the adapter at the specified
7307 * I/O port and with the specified bus type.
7308 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007309static ushort __devinit AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007310{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007311 ushort cfg_lsw;
7312 ushort bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007313
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007314 /*
7315 * The PCI BIOS is re-located by the motherboard BIOS. Because
7316 * of this the driver can not determine where a PCI BIOS is
7317 * loaded and executes.
7318 */
7319 if (bus_type & ASC_IS_PCI) {
7320 return (0);
7321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007322#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007323 if ((bus_type & ASC_IS_EISA) != 0) {
7324 cfg_lsw = AscGetEisaChipCfg(iop_base);
7325 cfg_lsw &= 0x000F;
7326 bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
7327 (cfg_lsw * ASC_BIOS_BANK_SIZE));
7328 return (bios_addr);
7329 } /* if */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007330#endif /* CONFIG_ISA */
7331
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007332 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007333
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007334 /*
7335 * ISA PnP uses the top bit as the 32K BIOS flag
7336 */
7337 if (bus_type == ASC_IS_ISAPNP) {
7338 cfg_lsw &= 0x7FFF;
7339 }
7340 /* if */
7341 bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
7342 ASC_BIOS_MIN_ADDR);
7343 return (bios_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007344}
7345
Linus Torvalds1da177e2005-04-16 15:20:36 -07007346/*
7347 * --- Functions Required by the Adv Library
7348 */
7349
7350/*
7351 * DvcGetPhyAddr()
7352 *
7353 * Return the physical address of 'vaddr' and set '*lenp' to the
7354 * number of physically contiguous bytes that follow 'vaddr'.
7355 * 'flag' indicates the type of structure whose physical address
7356 * is being translated.
7357 *
7358 * Note: Because Linux currently doesn't page the kernel and all
7359 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7360 */
7361ADV_PADDR
7362DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007363 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007364{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007365 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007366
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007367 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007368
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007369 ASC_DBG4(4,
7370 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7371 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7372 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007373
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007374 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007375}
7376
7377/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007378 * --- Tracing and Debugging Functions
7379 */
7380
7381#ifdef ADVANSYS_STATS
7382#ifdef CONFIG_PROC_FS
7383/*
7384 * asc_prt_board_stats()
7385 *
7386 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7387 * cf. asc_prt_line().
7388 *
7389 * Return the number of characters copied into 'cp'. No more than
7390 * 'cplen' characters will be copied to 'cp'.
7391 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007392static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007393{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007394 int leftlen;
7395 int totlen;
7396 int len;
7397 struct asc_stats *s;
7398 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007399
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007400 leftlen = cplen;
7401 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007402
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007403 boardp = ASC_BOARDP(shost);
7404 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007405
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007406 len = asc_prt_line(cp, leftlen,
7407 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7408 shost->host_no);
7409 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007410
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007411 len = asc_prt_line(cp, leftlen,
7412 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7413 s->queuecommand, s->reset, s->biosparam,
7414 s->interrupt);
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,
7418 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7419 s->callback, s->done, s->build_error,
7420 s->adv_build_noreq, s->adv_build_nosg);
7421 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007422
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007423 len = asc_prt_line(cp, leftlen,
7424 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7425 s->exe_noerror, s->exe_busy, s->exe_error,
7426 s->exe_unknown);
7427 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007428
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007429 /*
7430 * Display data transfer statistics.
7431 */
7432 if (s->cont_cnt > 0) {
7433 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7434 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007436 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7437 s->cont_xfer / 2,
7438 ASC_TENTHS(s->cont_xfer, 2));
7439 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007440
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007441 /* Contiguous transfer average size */
7442 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7443 (s->cont_xfer / 2) / s->cont_cnt,
7444 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7445 ASC_PRT_NEXT();
7446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007447
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007448 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007450 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7451 s->sg_cnt, s->sg_elem);
7452 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007453
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007454 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7455 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7456 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007457
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007458 /* Scatter gather transfer statistics */
7459 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7460 s->sg_elem / s->sg_cnt,
7461 ASC_TENTHS(s->sg_elem, s->sg_cnt));
7462 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007463
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007464 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
7465 (s->sg_xfer / 2) / s->sg_elem,
7466 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7467 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007468
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007469 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7470 (s->sg_xfer / 2) / s->sg_cnt,
7471 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7472 ASC_PRT_NEXT();
7473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007474
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007475 /*
7476 * Display request queuing statistics.
7477 */
7478 len = asc_prt_line(cp, leftlen,
7479 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7480 HZ);
7481 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007482
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007483 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007484}
7485
7486/*
7487 * asc_prt_target_stats()
7488 *
7489 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7490 * cf. asc_prt_line().
7491 *
7492 * This is separated from asc_prt_board_stats because a full set
7493 * of targets will overflow ASC_PRTBUF_SIZE.
7494 *
7495 * Return the number of characters copied into 'cp'. No more than
7496 * 'cplen' characters will be copied to 'cp'.
7497 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007498static int
7499asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007500{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007501 int leftlen;
7502 int totlen;
7503 int len;
7504 struct asc_stats *s;
7505 ushort chip_scsi_id;
7506 asc_board_t *boardp;
7507 asc_queue_t *active;
7508 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007509
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007510 leftlen = cplen;
7511 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007512
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007513 boardp = ASC_BOARDP(shost);
7514 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007515
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007516 active = &ASC_BOARDP(shost)->active;
7517 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007518
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007519 if (ASC_NARROW_BOARD(boardp)) {
7520 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7521 } else {
7522 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007524
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007525 if ((chip_scsi_id == tgt_id) ||
7526 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7527 return 0;
7528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007529
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007530 do {
7531 if (active->q_tot_cnt[tgt_id] > 0
7532 || waiting->q_tot_cnt[tgt_id] > 0) {
7533 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
7534 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007535
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007536 len = asc_prt_line(cp, leftlen,
7537 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7538 active->q_cur_cnt[tgt_id],
7539 active->q_max_cnt[tgt_id],
7540 active->q_tot_cnt[tgt_id],
7541 active->q_min_tim[tgt_id],
7542 active->q_max_tim[tgt_id],
7543 (active->q_tot_cnt[tgt_id] ==
7544 0) ? 0 : (active->
7545 q_tot_tim[tgt_id] /
7546 active->
7547 q_tot_cnt[tgt_id]),
7548 (active->q_tot_cnt[tgt_id] ==
7549 0) ? 0 : ASC_TENTHS(active->
7550 q_tot_tim
7551 [tgt_id],
7552 active->
7553 q_tot_cnt
7554 [tgt_id]));
7555 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007556
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007557 len = asc_prt_line(cp, leftlen,
7558 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7559 waiting->q_cur_cnt[tgt_id],
7560 waiting->q_max_cnt[tgt_id],
7561 waiting->q_tot_cnt[tgt_id],
7562 waiting->q_min_tim[tgt_id],
7563 waiting->q_max_tim[tgt_id],
7564 (waiting->q_tot_cnt[tgt_id] ==
7565 0) ? 0 : (waiting->
7566 q_tot_tim[tgt_id] /
7567 waiting->
7568 q_tot_cnt[tgt_id]),
7569 (waiting->q_tot_cnt[tgt_id] ==
7570 0) ? 0 : ASC_TENTHS(waiting->
7571 q_tot_tim
7572 [tgt_id],
7573 waiting->
7574 q_tot_cnt
7575 [tgt_id]));
7576 ASC_PRT_NEXT();
7577 }
7578 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007579
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007580 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007581}
7582#endif /* CONFIG_PROC_FS */
7583#endif /* ADVANSYS_STATS */
7584
7585#ifdef ADVANSYS_DEBUG
7586/*
7587 * asc_prt_scsi_host()
7588 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007589static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007590{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007591 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007592
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007593 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007594
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007595 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7596 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7597 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007598
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007599 printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
7600 (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007601
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007602 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7603 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007604
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007605 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7606 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007607
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007608 if (ASC_NARROW_BOARD(boardp)) {
7609 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7610 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7611 } else {
7612 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7613 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007615}
7616
7617/*
7618 * asc_prt_scsi_cmnd()
7619 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007620static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007621{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007622 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007623
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007624 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7625 (ulong)s->device->host, (ulong)s->device, s->device->id,
7626 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007627
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007628 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007629
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007630 printk("sc_data_direction %u, resid %d\n",
7631 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007632
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007633 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007634
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007635 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7636 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007637
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007638 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007639
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007640 printk
7641 (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
7642 (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble,
7643 s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007644
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007645 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007646}
7647
7648/*
7649 * asc_prt_asc_dvc_var()
7650 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007651static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007652{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007653 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007654
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007655 printk
7656 (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
7657 h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007658
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007659 printk
7660 (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
7661 h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback,
7662 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007663
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007664 printk
7665 (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
7666 (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng,
7667 (unsigned)h->unit_not_ready, (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007668
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007669 printk
7670 (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
7671 (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor,
7672 (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007673
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007674 printk
7675 (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
7676 (unsigned)h->is_in_int, (unsigned)h->max_total_qng,
7677 (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007678
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007679 printk
7680 (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
7681 (unsigned)h->last_q_shortage, (unsigned)h->init_state,
7682 (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007683
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007684 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007685}
7686
7687/*
7688 * asc_prt_asc_dvc_cfg()
7689 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007690static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007691{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007692 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007693
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007694 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7695 h->can_tagged_qng, h->cmd_qng_enabled);
7696 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7697 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007698
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007699 printk
7700 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7701 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7702 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007703
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007704 printk
7705 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7706 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7707 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007708
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007709 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7710 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007711}
7712
7713/*
7714 * asc_prt_asc_scsi_q()
7715 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007716static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007717{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007718 ASC_SG_HEAD *sgp;
7719 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007720
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007721 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007722
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007723 printk
7724 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7725 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7726 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007727
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007728 printk
7729 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7730 (ulong)le32_to_cpu(q->q1.data_addr),
7731 (ulong)le32_to_cpu(q->q1.data_cnt),
7732 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007733
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007734 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
7735 (ulong)q->cdbptr, q->q2.cdb_len,
7736 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007737
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007738 if (q->sg_head) {
7739 sgp = q->sg_head;
7740 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
7741 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
7742 sgp->queue_cnt);
7743 for (i = 0; i < sgp->entry_cnt; i++) {
7744 printk(" [%u]: addr 0x%lx, bytes %lu\n",
7745 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
7746 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
7747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007748
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007750}
7751
7752/*
7753 * asc_prt_asc_qdone_info()
7754 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007755static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007756{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007757 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
7758 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
7759 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
7760 q->d2.tag_code);
7761 printk
7762 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
7763 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007764}
7765
7766/*
7767 * asc_prt_adv_dvc_var()
7768 *
7769 * Display an ADV_DVC_VAR structure.
7770 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007771static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007772{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007773 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007774
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007775 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
7776 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007777
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007778 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
7779 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
7780 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007781
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007782 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
7783 (unsigned)h->start_motor,
7784 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007785
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007786 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
7787 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
7788 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007790 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
7791 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007792
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007793 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
7794 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007795
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007796 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
7797 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007798}
7799
7800/*
7801 * asc_prt_adv_dvc_cfg()
7802 *
7803 * Display an ADV_DVC_CFG structure.
7804 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007805static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007806{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007807 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007808
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007809 printk(" disc_enable 0x%x, termination 0x%x\n",
7810 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007811
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007812 printk(" chip_version 0x%x, mcode_date 0x%x\n",
7813 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007814
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007815 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
7816 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007817
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007818 printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
7819 h->control_flag, h->pci_slot_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007820}
7821
7822/*
7823 * asc_prt_adv_scsi_req_q()
7824 *
7825 * Display an ADV_SCSI_REQ_Q structure.
7826 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007827static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007828{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007829 int sg_blk_cnt;
7830 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007831
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007832 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007833
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007834 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
7835 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007836
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007837 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
7838 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007839
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007840 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7841 (ulong)le32_to_cpu(q->data_cnt),
7842 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007843
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007844 printk
7845 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
7846 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007847
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007848 printk(" sg_working_ix 0x%x, target_cmd %u\n",
7849 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007851 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
7852 (ulong)le32_to_cpu(q->scsiq_rptr),
7853 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007854
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007855 /* Display the request's ADV_SG_BLOCK structures. */
7856 if (q->sg_list_ptr != NULL) {
7857 sg_blk_cnt = 0;
7858 while (1) {
7859 /*
7860 * 'sg_ptr' is a physical address. Convert it to a virtual
7861 * address by indexing 'sg_blk_cnt' into the virtual address
7862 * array 'sg_list_ptr'.
7863 *
7864 * XXX - Assumes all SG physical blocks are virtually contiguous.
7865 */
7866 sg_ptr =
7867 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
7868 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
7869 if (sg_ptr->sg_ptr == 0) {
7870 break;
7871 }
7872 sg_blk_cnt++;
7873 }
7874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007875}
7876
7877/*
7878 * asc_prt_adv_sgblock()
7879 *
7880 * Display an ADV_SG_BLOCK structure.
7881 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007882static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007883{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007884 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007885
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007886 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
7887 (ulong)b, sgblockno);
7888 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
7889 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
7890 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
7891 if (b->sg_ptr != 0) {
7892 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
7893 }
7894 for (i = 0; i < b->sg_cnt; i++) {
7895 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
7896 i, (ulong)b->sg_list[i].sg_addr,
7897 (ulong)b->sg_list[i].sg_count);
7898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007899}
7900
7901/*
7902 * asc_prt_hex()
7903 *
7904 * Print hexadecimal output in 4 byte groupings 32 bytes
7905 * or 8 double-words per line.
7906 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007907static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007908{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007909 int i;
7910 int j;
7911 int k;
7912 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007913
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007914 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007915
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007916 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007917
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007918 /* Display a maximum of 8 double-words per line. */
7919 if ((k = (l - i) / 4) >= 8) {
7920 k = 8;
7921 m = 0;
7922 } else {
7923 m = (l - i) % 4;
7924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007925
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007926 for (j = 0; j < k; j++) {
7927 printk(" %2.2X%2.2X%2.2X%2.2X",
7928 (unsigned)s[i + (j * 4)],
7929 (unsigned)s[i + (j * 4) + 1],
7930 (unsigned)s[i + (j * 4) + 2],
7931 (unsigned)s[i + (j * 4) + 3]);
7932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007933
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007934 switch (m) {
7935 case 0:
7936 default:
7937 break;
7938 case 1:
7939 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
7940 break;
7941 case 2:
7942 printk(" %2.2X%2.2X",
7943 (unsigned)s[i + (j * 4)],
7944 (unsigned)s[i + (j * 4) + 1]);
7945 break;
7946 case 3:
7947 printk(" %2.2X%2.2X%2.2X",
7948 (unsigned)s[i + (j * 4) + 1],
7949 (unsigned)s[i + (j * 4) + 2],
7950 (unsigned)s[i + (j * 4) + 3]);
7951 break;
7952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007953
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007954 printk("\n");
7955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007956}
7957#endif /* ADVANSYS_DEBUG */
7958
7959/*
7960 * --- Asc Library Functions
7961 */
7962
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007963static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007964{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007965 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007966
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007967 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7968 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
7969 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007970}
7971
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007972static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007973{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007974 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007975
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007976 if (AscGetChipScsiID(iop_base) == new_host_id) {
7977 return (new_host_id);
7978 }
7979 cfg_lsw = AscGetChipCfgLsw(iop_base);
7980 cfg_lsw &= 0xF8FF;
7981 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
7982 AscSetChipCfgLsw(iop_base, cfg_lsw);
7983 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007984}
7985
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007986static uchar __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007987{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007988 uchar sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007989
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007990 AscSetBank(iop_base, 1);
7991 sc = inp(iop_base + IOP_REG_SC);
7992 AscSetBank(iop_base, 0);
7993 return (sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007994}
7995
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007996static uchar __devinit AscGetChipVersion(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007997{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007998 if ((bus_type & ASC_IS_EISA) != 0) {
7999 PortAddr eisa_iop;
8000 uchar revision;
8001 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
8002 (PortAddr) ASC_EISA_REV_IOP_MASK;
8003 revision = inp(eisa_iop);
8004 return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision));
8005 }
8006 return (AscGetChipVerNo(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008007}
8008
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008009static ushort __devinit AscGetChipBusType(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008010{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008011 ushort chip_ver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008012
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008013 chip_ver = AscGetChipVerNo(iop_base);
8014 if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
8015 && (chip_ver <= ASC_CHIP_MAX_VER_VL)
8016 ) {
8017 if (((iop_base & 0x0C30) == 0x0C30)
8018 || ((iop_base & 0x0C50) == 0x0C50)
8019 ) {
8020 return (ASC_IS_EISA);
8021 }
8022 return (ASC_IS_VL);
8023 }
8024 if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
8025 (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
8026 if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
8027 return (ASC_IS_ISAPNP);
8028 }
8029 return (ASC_IS_ISA);
8030 } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
8031 (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
8032 return (ASC_IS_PCI);
8033 }
8034 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008035}
8036
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008037static ASC_DCNT
8038AscLoadMicroCode(PortAddr iop_base,
8039 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008040{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008041 ASC_DCNT chksum;
8042 ushort mcode_word_size;
8043 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008044
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008045 /* Write the microcode buffer starting at LRAM address 0. */
8046 mcode_word_size = (ushort)(mcode_size >> 1);
8047 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
8048 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008049
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008050 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
8051 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
8052 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
8053 (ushort)ASC_CODE_SEC_BEG,
8054 (ushort)((mcode_size -
8055 s_addr - (ushort)
8056 ASC_CODE_SEC_BEG) /
8057 2));
8058 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
8059 (ulong)mcode_chksum);
8060 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
8061 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
8062 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008063}
8064
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008065static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008066{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008067 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008068
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008069 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
8070 iop_base, AscGetChipSignatureByte(iop_base));
8071 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
8072 ASC_DBG2(1,
8073 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
8074 iop_base, AscGetChipSignatureWord(iop_base));
8075 sig_word = AscGetChipSignatureWord(iop_base);
8076 if ((sig_word == (ushort)ASC_1000_ID0W) ||
8077 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
8078 return (1);
8079 }
8080 }
8081 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008082}
8083
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008084static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008085{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008086 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
8087 AscSetChipStatus(iop_base, 0);
8088 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008089}
8090
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008091static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008092{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008093 ushort cfg_lsw;
8094 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008095
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008096 if ((bus_type & ASC_IS_EISA) != 0) {
8097 cfg_lsw = AscGetEisaChipCfg(iop_base);
8098 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8099 if ((chip_irq == 13) || (chip_irq > 15)) {
8100 return (0);
8101 }
8102 return (chip_irq);
8103 }
8104 if ((bus_type & ASC_IS_VL) != 0) {
8105 cfg_lsw = AscGetChipCfgLsw(iop_base);
8106 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8107 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8108 return (0);
8109 }
8110 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8111 }
8112 cfg_lsw = AscGetChipCfgLsw(iop_base);
8113 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8114 if (chip_irq == 3)
8115 chip_irq += (uchar)2;
8116 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008117}
8118
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008119static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008120AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008121{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008122 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008123
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008124 if ((bus_type & ASC_IS_VL) != 0) {
8125 if (irq_no != 0) {
8126 if ((irq_no < ASC_MIN_IRQ_NO)
8127 || (irq_no > ASC_MAX_IRQ_NO)) {
8128 irq_no = 0;
8129 } else {
8130 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8131 }
8132 }
8133 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8134 cfg_lsw |= (ushort)0x0010;
8135 AscSetChipCfgLsw(iop_base, cfg_lsw);
8136 AscToggleIRQAct(iop_base);
8137 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8138 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8139 AscSetChipCfgLsw(iop_base, cfg_lsw);
8140 AscToggleIRQAct(iop_base);
8141 return (AscGetChipIRQ(iop_base, bus_type));
8142 }
8143 if ((bus_type & (ASC_IS_ISA)) != 0) {
8144 if (irq_no == 15)
8145 irq_no -= (uchar)2;
8146 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8147 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8148 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8149 AscSetChipCfgLsw(iop_base, cfg_lsw);
8150 return (AscGetChipIRQ(iop_base, bus_type));
8151 }
8152 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008153}
8154
8155#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008156static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008157{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008158 if (dma_channel < 4) {
8159 outp(0x000B, (ushort)(0xC0 | dma_channel));
8160 outp(0x000A, dma_channel);
8161 } else if (dma_channel < 8) {
8162 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8163 outp(0x00D4, (ushort)(dma_channel - 4));
8164 }
8165 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008166}
8167#endif /* CONFIG_ISA */
8168
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008169static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008170{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008171 EXT_MSG ext_msg;
8172 EXT_MSG out_msg;
8173 ushort halt_q_addr;
8174 int sdtr_accept;
8175 ushort int_halt_code;
8176 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8177 ASC_SCSI_BIT_ID_TYPE target_id;
8178 PortAddr iop_base;
8179 uchar tag_code;
8180 uchar q_status;
8181 uchar halt_qp;
8182 uchar sdtr_data;
8183 uchar target_ix;
8184 uchar q_cntl, tid_no;
8185 uchar cur_dvc_qng;
8186 uchar asyn_sdtr;
8187 uchar scsi_status;
8188 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008189
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008190 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8191 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008193 iop_base = asc_dvc->iop_base;
8194 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008195
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008196 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8197 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8198 target_ix = AscReadLramByte(iop_base,
8199 (ushort)(halt_q_addr +
8200 (ushort)ASC_SCSIQ_B_TARGET_IX));
8201 q_cntl =
8202 AscReadLramByte(iop_base,
8203 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8204 tid_no = ASC_TIX_TO_TID(target_ix);
8205 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8206 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8207 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8208 } else {
8209 asyn_sdtr = 0;
8210 }
8211 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8212 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8213 AscSetChipSDTR(iop_base, 0, tid_no);
8214 boardp->sdtr_data[tid_no] = 0;
8215 }
8216 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8217 return (0);
8218 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8219 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8220 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8221 boardp->sdtr_data[tid_no] = asyn_sdtr;
8222 }
8223 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8224 return (0);
8225 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008226
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008227 AscMemWordCopyPtrFromLram(iop_base,
8228 ASCV_MSGIN_BEG,
8229 (uchar *)&ext_msg,
8230 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008231
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008232 if (ext_msg.msg_type == MS_EXTEND &&
8233 ext_msg.msg_req == MS_SDTR_CODE &&
8234 ext_msg.msg_len == MS_SDTR_LEN) {
8235 sdtr_accept = TRUE;
8236 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008237
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008238 sdtr_accept = FALSE;
8239 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8240 }
8241 if ((ext_msg.xfer_period <
8242 asc_dvc->sdtr_period_tbl[asc_dvc->
8243 host_init_sdtr_index])
8244 || (ext_msg.xfer_period >
8245 asc_dvc->sdtr_period_tbl[asc_dvc->
8246 max_sdtr_index])) {
8247 sdtr_accept = FALSE;
8248 ext_msg.xfer_period =
8249 asc_dvc->sdtr_period_tbl[asc_dvc->
8250 host_init_sdtr_index];
8251 }
8252 if (sdtr_accept) {
8253 sdtr_data =
8254 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8255 ext_msg.req_ack_offset);
8256 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008257
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008258 q_cntl |= QC_MSG_OUT;
8259 asc_dvc->init_sdtr &= ~target_id;
8260 asc_dvc->sdtr_done &= ~target_id;
8261 AscSetChipSDTR(iop_base, asyn_sdtr,
8262 tid_no);
8263 boardp->sdtr_data[tid_no] = asyn_sdtr;
8264 }
8265 }
8266 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008267
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008268 q_cntl &= ~QC_MSG_OUT;
8269 asc_dvc->init_sdtr &= ~target_id;
8270 asc_dvc->sdtr_done &= ~target_id;
8271 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8272 } else {
8273 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008274
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008275 q_cntl &= ~QC_MSG_OUT;
8276 asc_dvc->sdtr_done |= target_id;
8277 asc_dvc->init_sdtr |= target_id;
8278 asc_dvc->pci_fix_asyn_xfer &=
8279 ~target_id;
8280 sdtr_data =
8281 AscCalSDTRData(asc_dvc,
8282 ext_msg.xfer_period,
8283 ext_msg.
8284 req_ack_offset);
8285 AscSetChipSDTR(iop_base, sdtr_data,
8286 tid_no);
8287 boardp->sdtr_data[tid_no] = sdtr_data;
8288 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008289
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008290 q_cntl |= QC_MSG_OUT;
8291 AscMsgOutSDTR(asc_dvc,
8292 ext_msg.xfer_period,
8293 ext_msg.req_ack_offset);
8294 asc_dvc->pci_fix_asyn_xfer &=
8295 ~target_id;
8296 sdtr_data =
8297 AscCalSDTRData(asc_dvc,
8298 ext_msg.xfer_period,
8299 ext_msg.
8300 req_ack_offset);
8301 AscSetChipSDTR(iop_base, sdtr_data,
8302 tid_no);
8303 boardp->sdtr_data[tid_no] = sdtr_data;
8304 asc_dvc->sdtr_done |= target_id;
8305 asc_dvc->init_sdtr |= target_id;
8306 }
8307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008308
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008309 AscWriteLramByte(iop_base,
8310 (ushort)(halt_q_addr +
8311 (ushort)ASC_SCSIQ_B_CNTL),
8312 q_cntl);
8313 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8314 return (0);
8315 } else if (ext_msg.msg_type == MS_EXTEND &&
8316 ext_msg.msg_req == MS_WDTR_CODE &&
8317 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008318
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008319 ext_msg.wdtr_width = 0;
8320 AscMemWordCopyPtrToLram(iop_base,
8321 ASCV_MSGOUT_BEG,
8322 (uchar *)&ext_msg,
8323 sizeof(EXT_MSG) >> 1);
8324 q_cntl |= QC_MSG_OUT;
8325 AscWriteLramByte(iop_base,
8326 (ushort)(halt_q_addr +
8327 (ushort)ASC_SCSIQ_B_CNTL),
8328 q_cntl);
8329 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8330 return (0);
8331 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008332
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008333 ext_msg.msg_type = MESSAGE_REJECT;
8334 AscMemWordCopyPtrToLram(iop_base,
8335 ASCV_MSGOUT_BEG,
8336 (uchar *)&ext_msg,
8337 sizeof(EXT_MSG) >> 1);
8338 q_cntl |= QC_MSG_OUT;
8339 AscWriteLramByte(iop_base,
8340 (ushort)(halt_q_addr +
8341 (ushort)ASC_SCSIQ_B_CNTL),
8342 q_cntl);
8343 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8344 return (0);
8345 }
8346 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008347
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008348 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008349
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008350 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008351
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008352 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008353
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008354 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8355 q_cntl |= QC_MSG_OUT;
8356 AscMsgOutSDTR(asc_dvc,
8357 asc_dvc->
8358 sdtr_period_tbl[(sdtr_data >> 4) &
8359 (uchar)(asc_dvc->
8360 max_sdtr_index -
8361 1)],
8362 (uchar)(sdtr_data & (uchar)
8363 ASC_SYN_MAX_OFFSET));
8364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008365
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008366 AscWriteLramByte(iop_base,
8367 (ushort)(halt_q_addr +
8368 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008369
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008370 tag_code = AscReadLramByte(iop_base,
8371 (ushort)(halt_q_addr + (ushort)
8372 ASC_SCSIQ_B_TAG_CODE));
8373 tag_code &= 0xDC;
8374 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8375 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8376 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008377
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008378 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8379 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008380
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008381 }
8382 AscWriteLramByte(iop_base,
8383 (ushort)(halt_q_addr +
8384 (ushort)ASC_SCSIQ_B_TAG_CODE),
8385 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008386
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008387 q_status = AscReadLramByte(iop_base,
8388 (ushort)(halt_q_addr + (ushort)
8389 ASC_SCSIQ_B_STATUS));
8390 q_status |= (QS_READY | QS_BUSY);
8391 AscWriteLramByte(iop_base,
8392 (ushort)(halt_q_addr +
8393 (ushort)ASC_SCSIQ_B_STATUS),
8394 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008395
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008396 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8397 scsi_busy &= ~target_id;
8398 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008399
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008400 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8401 return (0);
8402 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008403
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008404 AscMemWordCopyPtrFromLram(iop_base,
8405 ASCV_MSGOUT_BEG,
8406 (uchar *)&out_msg,
8407 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008408
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008409 if ((out_msg.msg_type == MS_EXTEND) &&
8410 (out_msg.msg_len == MS_SDTR_LEN) &&
8411 (out_msg.msg_req == MS_SDTR_CODE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008412
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008413 asc_dvc->init_sdtr &= ~target_id;
8414 asc_dvc->sdtr_done &= ~target_id;
8415 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8416 boardp->sdtr_data[tid_no] = asyn_sdtr;
8417 }
8418 q_cntl &= ~QC_MSG_OUT;
8419 AscWriteLramByte(iop_base,
8420 (ushort)(halt_q_addr +
8421 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8422 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8423 return (0);
8424 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008425
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008426 scsi_status = AscReadLramByte(iop_base,
8427 (ushort)((ushort)halt_q_addr +
8428 (ushort)
8429 ASC_SCSIQ_SCSI_STATUS));
8430 cur_dvc_qng =
8431 AscReadLramByte(iop_base,
8432 (ushort)((ushort)ASC_QADR_BEG +
8433 (ushort)target_ix));
8434 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008435
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008436 scsi_busy = AscReadLramByte(iop_base,
8437 (ushort)ASCV_SCSIBUSY_B);
8438 scsi_busy |= target_id;
8439 AscWriteLramByte(iop_base,
8440 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8441 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008442
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008443 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8444 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8445 cur_dvc_qng -= 1;
8446 asc_dvc->max_dvc_qng[tid_no] =
8447 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008448
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008449 AscWriteLramByte(iop_base,
8450 (ushort)((ushort)
8451 ASCV_MAX_DVC_QNG_BEG
8452 + (ushort)
8453 tid_no),
8454 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008455
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008456 /*
8457 * Set the device queue depth to the number of
8458 * active requests when the QUEUE FULL condition
8459 * was encountered.
8460 */
8461 boardp->queue_full |= target_id;
8462 boardp->queue_full_cnt[tid_no] =
8463 cur_dvc_qng;
8464 }
8465 }
8466 }
8467 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8468 return (0);
8469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008470#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008471 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8472 uchar q_no;
8473 ushort q_addr;
8474 uchar sg_wk_q_no;
8475 uchar first_sg_wk_q_no;
8476 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8477 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8478 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8479 ushort sg_list_dwords;
8480 ushort sg_entry_cnt;
8481 uchar next_qp;
8482 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008483
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008484 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8485 if (q_no == ASC_QLINK_END) {
8486 return (0);
8487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008488
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008489 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008490
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008491 /*
8492 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8493 * structure pointer using a macro provided by the driver.
8494 * The ASC_SCSI_REQ pointer provides a pointer to the
8495 * host ASC_SG_HEAD structure.
8496 */
8497 /* Read request's SRB pointer. */
8498 scsiq = (ASC_SCSI_Q *)
8499 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8500 (ushort)
8501 (q_addr +
8502 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008503
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008504 /*
8505 * Get request's first and working SG queue.
8506 */
8507 sg_wk_q_no = AscReadLramByte(iop_base,
8508 (ushort)(q_addr +
8509 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008510
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008511 first_sg_wk_q_no = AscReadLramByte(iop_base,
8512 (ushort)(q_addr +
8513 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008514
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008515 /*
8516 * Reset request's working SG queue back to the
8517 * first SG queue.
8518 */
8519 AscWriteLramByte(iop_base,
8520 (ushort)(q_addr +
8521 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8522 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008523
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008524 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008525
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008526 /*
8527 * Set sg_entry_cnt to the number of SG elements
8528 * that will be completed on this interrupt.
8529 *
8530 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8531 * SG elements. The data_cnt and data_addr fields which
8532 * add 1 to the SG element capacity are not used when
8533 * restarting SG handling after a halt.
8534 */
8535 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8536 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008537
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008538 /*
8539 * Keep track of remaining number of SG elements that will
8540 * need to be handled on the next interrupt.
8541 */
8542 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8543 } else {
8544 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8545 scsiq->remain_sg_entry_cnt = 0;
8546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008547
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008548 /*
8549 * Copy SG elements into the list of allocated SG queues.
8550 *
8551 * Last index completed is saved in scsiq->next_sg_index.
8552 */
8553 next_qp = first_sg_wk_q_no;
8554 q_addr = ASC_QNO_TO_QADDR(next_qp);
8555 scsi_sg_q.sg_head_qp = q_no;
8556 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8557 for (i = 0; i < sg_head->queue_cnt; i++) {
8558 scsi_sg_q.seq_no = i + 1;
8559 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8560 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8561 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8562 /*
8563 * After very first SG queue RISC FW uses next
8564 * SG queue first element then checks sg_list_cnt
8565 * against zero and then decrements, so set
8566 * sg_list_cnt 1 less than number of SG elements
8567 * in each SG queue.
8568 */
8569 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8570 scsi_sg_q.sg_cur_list_cnt =
8571 ASC_SG_LIST_PER_Q - 1;
8572 } else {
8573 /*
8574 * This is the last SG queue in the list of
8575 * allocated SG queues. If there are more
8576 * SG elements than will fit in the allocated
8577 * queues, then set the QCSG_SG_XFER_MORE flag.
8578 */
8579 if (scsiq->remain_sg_entry_cnt != 0) {
8580 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8581 } else {
8582 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8583 }
8584 /* equals sg_entry_cnt * 2 */
8585 sg_list_dwords = sg_entry_cnt << 1;
8586 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8587 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8588 sg_entry_cnt = 0;
8589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008590
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008591 scsi_sg_q.q_no = next_qp;
8592 AscMemWordCopyPtrToLram(iop_base,
8593 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8594 (uchar *)&scsi_sg_q,
8595 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008596
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008597 AscMemDWordCopyPtrToLram(iop_base,
8598 q_addr + ASC_SGQ_LIST_BEG,
8599 (uchar *)&sg_head->
8600 sg_list[scsiq->next_sg_index],
8601 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008602
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008603 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008604
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008605 /*
8606 * If the just completed SG queue contained the
8607 * last SG element, then no more SG queues need
8608 * to be written.
8609 */
8610 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8611 break;
8612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008613
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008614 next_qp = AscReadLramByte(iop_base,
8615 (ushort)(q_addr +
8616 ASC_SCSIQ_B_FWD));
8617 q_addr = ASC_QNO_TO_QADDR(next_qp);
8618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008619
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008620 /*
8621 * Clear the halt condition so the RISC will be restarted
8622 * after the return.
8623 */
8624 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8625 return (0);
8626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008627#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008628 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008629}
8630
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008631static uchar
8632_AscCopyLramScsiDoneQ(PortAddr iop_base,
8633 ushort q_addr,
8634 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008635{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008636 ushort _val;
8637 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008638
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008639 DvcGetQinfo(iop_base,
8640 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8641 (uchar *)scsiq,
8642 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008643
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008644 _val = AscReadLramWord(iop_base,
8645 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8646 scsiq->q_status = (uchar)_val;
8647 scsiq->q_no = (uchar)(_val >> 8);
8648 _val = AscReadLramWord(iop_base,
8649 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8650 scsiq->cntl = (uchar)_val;
8651 sg_queue_cnt = (uchar)(_val >> 8);
8652 _val = AscReadLramWord(iop_base,
8653 (ushort)(q_addr +
8654 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8655 scsiq->sense_len = (uchar)_val;
8656 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008657
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008658 /*
8659 * Read high word of remain bytes from alternate location.
8660 */
8661 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
8662 (ushort)(q_addr +
8663 (ushort)
8664 ASC_SCSIQ_W_ALT_DC1)))
8665 << 16);
8666 /*
8667 * Read low word of remain bytes from original location.
8668 */
8669 scsiq->remain_bytes += AscReadLramWord(iop_base,
8670 (ushort)(q_addr + (ushort)
8671 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008672
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008673 scsiq->remain_bytes &= max_dma_count;
8674 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008675}
8676
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008677static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008678{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008679 uchar next_qp;
8680 uchar n_q_used;
8681 uchar sg_list_qp;
8682 uchar sg_queue_cnt;
8683 uchar q_cnt;
8684 uchar done_q_tail;
8685 uchar tid_no;
8686 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8687 ASC_SCSI_BIT_ID_TYPE target_id;
8688 PortAddr iop_base;
8689 ushort q_addr;
8690 ushort sg_q_addr;
8691 uchar cur_target_qng;
8692 ASC_QDONE_INFO scsiq_buf;
8693 ASC_QDONE_INFO *scsiq;
8694 int false_overrun;
8695 ASC_ISR_CALLBACK asc_isr_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008696
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008697 iop_base = asc_dvc->iop_base;
8698 asc_isr_callback = asc_dvc->isr_callback;
8699 n_q_used = 1;
8700 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
8701 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
8702 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
8703 next_qp = AscReadLramByte(iop_base,
8704 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
8705 if (next_qp != ASC_QLINK_END) {
8706 AscPutVarDoneQTail(iop_base, next_qp);
8707 q_addr = ASC_QNO_TO_QADDR(next_qp);
8708 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
8709 asc_dvc->max_dma_count);
8710 AscWriteLramByte(iop_base,
8711 (ushort)(q_addr +
8712 (ushort)ASC_SCSIQ_B_STATUS),
8713 (uchar)(scsiq->
8714 q_status & (uchar)~(QS_READY |
8715 QS_ABORTED)));
8716 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
8717 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
8718 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
8719 sg_q_addr = q_addr;
8720 sg_list_qp = next_qp;
8721 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
8722 sg_list_qp = AscReadLramByte(iop_base,
8723 (ushort)(sg_q_addr
8724 + (ushort)
8725 ASC_SCSIQ_B_FWD));
8726 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
8727 if (sg_list_qp == ASC_QLINK_END) {
8728 AscSetLibErrorCode(asc_dvc,
8729 ASCQ_ERR_SG_Q_LINKS);
8730 scsiq->d3.done_stat = QD_WITH_ERROR;
8731 scsiq->d3.host_stat =
8732 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
8733 goto FATAL_ERR_QDONE;
8734 }
8735 AscWriteLramByte(iop_base,
8736 (ushort)(sg_q_addr + (ushort)
8737 ASC_SCSIQ_B_STATUS),
8738 QS_FREE);
8739 }
8740 n_q_used = sg_queue_cnt + 1;
8741 AscPutVarDoneQTail(iop_base, sg_list_qp);
8742 }
8743 if (asc_dvc->queue_full_or_busy & target_id) {
8744 cur_target_qng = AscReadLramByte(iop_base,
8745 (ushort)((ushort)
8746 ASC_QADR_BEG
8747 + (ushort)
8748 scsiq->d2.
8749 target_ix));
8750 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
8751 scsi_busy = AscReadLramByte(iop_base, (ushort)
8752 ASCV_SCSIBUSY_B);
8753 scsi_busy &= ~target_id;
8754 AscWriteLramByte(iop_base,
8755 (ushort)ASCV_SCSIBUSY_B,
8756 scsi_busy);
8757 asc_dvc->queue_full_or_busy &= ~target_id;
8758 }
8759 }
8760 if (asc_dvc->cur_total_qng >= n_q_used) {
8761 asc_dvc->cur_total_qng -= n_q_used;
8762 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
8763 asc_dvc->cur_dvc_qng[tid_no]--;
8764 }
8765 } else {
8766 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
8767 scsiq->d3.done_stat = QD_WITH_ERROR;
8768 goto FATAL_ERR_QDONE;
8769 }
8770 if ((scsiq->d2.srb_ptr == 0UL) ||
8771 ((scsiq->q_status & QS_ABORTED) != 0)) {
8772 return (0x11);
8773 } else if (scsiq->q_status == QS_DONE) {
8774 false_overrun = FALSE;
8775 if (scsiq->extra_bytes != 0) {
8776 scsiq->remain_bytes +=
8777 (ADV_DCNT)scsiq->extra_bytes;
8778 }
8779 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
8780 if (scsiq->d3.host_stat ==
8781 QHSTA_M_DATA_OVER_RUN) {
8782 if ((scsiq->
8783 cntl & (QC_DATA_IN | QC_DATA_OUT))
8784 == 0) {
8785 scsiq->d3.done_stat =
8786 QD_NO_ERROR;
8787 scsiq->d3.host_stat =
8788 QHSTA_NO_ERROR;
8789 } else if (false_overrun) {
8790 scsiq->d3.done_stat =
8791 QD_NO_ERROR;
8792 scsiq->d3.host_stat =
8793 QHSTA_NO_ERROR;
8794 }
8795 } else if (scsiq->d3.host_stat ==
8796 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
8797 AscStopChip(iop_base);
8798 AscSetChipControl(iop_base,
8799 (uchar)(CC_SCSI_RESET
8800 | CC_HALT));
8801 DvcDelayNanoSecond(asc_dvc, 60000);
8802 AscSetChipControl(iop_base, CC_HALT);
8803 AscSetChipStatus(iop_base,
8804 CIW_CLR_SCSI_RESET_INT);
8805 AscSetChipStatus(iop_base, 0);
8806 AscSetChipControl(iop_base, 0);
8807 }
8808 }
8809 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8810 (*asc_isr_callback) (asc_dvc, scsiq);
8811 } else {
8812 if ((AscReadLramByte(iop_base,
8813 (ushort)(q_addr + (ushort)
8814 ASC_SCSIQ_CDB_BEG))
8815 == START_STOP)) {
8816 asc_dvc->unit_not_ready &= ~target_id;
8817 if (scsiq->d3.done_stat != QD_NO_ERROR) {
8818 asc_dvc->start_motor &=
8819 ~target_id;
8820 }
8821 }
8822 }
8823 return (1);
8824 } else {
8825 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
8826 FATAL_ERR_QDONE:
8827 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8828 (*asc_isr_callback) (asc_dvc, scsiq);
8829 }
8830 return (0x80);
8831 }
8832 }
8833 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008834}
8835
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008836static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008837{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008838 ASC_CS_TYPE chipstat;
8839 PortAddr iop_base;
8840 ushort saved_ram_addr;
8841 uchar ctrl_reg;
8842 uchar saved_ctrl_reg;
8843 int int_pending;
8844 int status;
8845 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008846
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008847 iop_base = asc_dvc->iop_base;
8848 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008850 if (AscIsIntPending(iop_base) == 0) {
8851 return int_pending;
8852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008853
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008854 if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
8855 || (asc_dvc->isr_callback == 0)
8856 ) {
8857 return (ERR);
8858 }
8859 if (asc_dvc->in_critical_cnt != 0) {
8860 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
8861 return (ERR);
8862 }
8863 if (asc_dvc->is_in_int) {
8864 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
8865 return (ERR);
8866 }
8867 asc_dvc->is_in_int = TRUE;
8868 ctrl_reg = AscGetChipControl(iop_base);
8869 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
8870 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
8871 chipstat = AscGetChipStatus(iop_base);
8872 if (chipstat & CSW_SCSI_RESET_LATCH) {
8873 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
8874 int i = 10;
8875 int_pending = TRUE;
8876 asc_dvc->sdtr_done = 0;
8877 saved_ctrl_reg &= (uchar)(~CC_HALT);
8878 while ((AscGetChipStatus(iop_base) &
8879 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
8880 DvcSleepMilliSecond(100);
8881 }
8882 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
8883 AscSetChipControl(iop_base, CC_HALT);
8884 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
8885 AscSetChipStatus(iop_base, 0);
8886 chipstat = AscGetChipStatus(iop_base);
8887 }
8888 }
8889 saved_ram_addr = AscGetChipLramAddr(iop_base);
8890 host_flag = AscReadLramByte(iop_base,
8891 ASCV_HOST_FLAG_B) &
8892 (uchar)(~ASC_HOST_FLAG_IN_ISR);
8893 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
8894 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
8895 if ((chipstat & CSW_INT_PENDING)
8896 || (int_pending)
8897 ) {
8898 AscAckInterrupt(iop_base);
8899 int_pending = TRUE;
8900 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
8901 if (AscIsrChipHalted(asc_dvc) == ERR) {
8902 goto ISR_REPORT_QDONE_FATAL_ERROR;
8903 } else {
8904 saved_ctrl_reg &= (uchar)(~CC_HALT);
8905 }
8906 } else {
8907 ISR_REPORT_QDONE_FATAL_ERROR:
8908 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
8909 while (((status =
8910 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
8911 }
8912 } else {
8913 do {
8914 if ((status =
8915 AscIsrQDone(asc_dvc)) == 1) {
8916 break;
8917 }
8918 } while (status == 0x11);
8919 }
8920 if ((status & 0x80) != 0)
8921 int_pending = ERR;
8922 }
8923 }
8924 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
8925 AscSetChipLramAddr(iop_base, saved_ram_addr);
8926 AscSetChipControl(iop_base, saved_ctrl_reg);
8927 asc_dvc->is_in_int = FALSE;
8928 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008929}
8930
8931/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008932static uchar _asc_mcode_buf[] = {
8933 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8934 0x00, 0x00, 0x00, 0x00,
8935 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
8936 0x00, 0x00, 0x00, 0x00,
8937 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8938 0x00, 0x00, 0x00, 0x00,
8939 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8940 0x00, 0x00, 0x00, 0x00,
8941 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
8942 0x00, 0xFF, 0x00, 0x00,
8943 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
8944 0x00, 0x00, 0x00, 0x00,
8945 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
8946 0x00, 0x00, 0x00, 0x00,
8947 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
8948 0x00, 0x00, 0x00, 0x00,
8949 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
8950 0x03, 0x23, 0x36, 0x40,
8951 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
8952 0xC2, 0x00, 0x92, 0x80,
8953 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
8954 0xB6, 0x00, 0x92, 0x80,
8955 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
8956 0x92, 0x80, 0x80, 0x62,
8957 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
8958 0xCD, 0x04, 0x4D, 0x00,
8959 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
8960 0xE6, 0x84, 0xD2, 0xC1,
8961 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
8962 0xC6, 0x81, 0xC2, 0x88,
8963 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
8964 0x84, 0x97, 0x07, 0xA6,
8965 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
8966 0xC2, 0x88, 0xCE, 0x00,
8967 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
8968 0x80, 0x63, 0x07, 0xA6,
8969 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
8970 0x34, 0x01, 0x00, 0x33,
8971 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
8972 0x68, 0x98, 0x4D, 0x04,
8973 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
8974 0xF8, 0x88, 0xFB, 0x23,
8975 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
8976 0x00, 0x33, 0x0A, 0x00,
8977 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
8978 0xC2, 0x88, 0xCD, 0x04,
8979 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
8980 0x06, 0xAB, 0x82, 0x01,
8981 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
8982 0x3C, 0x01, 0x00, 0x05,
8983 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
8984 0x15, 0x23, 0xA1, 0x01,
8985 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
8986 0x06, 0x61, 0x00, 0xA0,
8987 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
8988 0xC2, 0x88, 0x06, 0x23,
8989 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
8990 0x57, 0x60, 0x00, 0xA0,
8991 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
8992 0x4B, 0x00, 0x06, 0x61,
8993 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
8994 0x4F, 0x00, 0x84, 0x97,
8995 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
8996 0x48, 0x04, 0x84, 0x80,
8997 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
8998 0x81, 0x73, 0x06, 0x29,
8999 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
9000 0x04, 0x98, 0xF0, 0x80,
9001 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
9002 0x34, 0x02, 0x03, 0xA6,
9003 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
9004 0x46, 0x82, 0xFE, 0x95,
9005 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
9006 0x07, 0xA6, 0x5A, 0x02,
9007 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
9008 0x48, 0x82, 0x60, 0x96,
9009 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
9010 0x04, 0x01, 0x0C, 0xDC,
9011 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
9012 0x6F, 0x00, 0xA5, 0x01,
9013 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
9014 0x02, 0xA6, 0xAA, 0x02,
9015 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
9016 0x01, 0xA6, 0xB4, 0x02,
9017 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
9018 0x80, 0x63, 0x00, 0x43,
9019 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
9020 0x04, 0x61, 0x84, 0x01,
9021 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
9022 0x00, 0x00, 0xEA, 0x82,
9023 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
9024 0x00, 0x33, 0x1F, 0x00,
9025 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
9026 0xB6, 0x2D, 0x01, 0xA6,
9027 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
9028 0x10, 0x03, 0x03, 0xA6,
9029 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
9030 0x7C, 0x95, 0xEE, 0x82,
9031 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
9032 0x04, 0x01, 0x2D, 0xC8,
9033 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
9034 0x05, 0x05, 0x86, 0x98,
9035 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
9036 0x3C, 0x04, 0x06, 0xA6,
9037 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
9038 0x7C, 0x95, 0x32, 0x83,
9039 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
9040 0xEB, 0x04, 0x00, 0x33,
9041 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
9042 0xFF, 0xA2, 0x7A, 0x03,
9043 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
9044 0x00, 0xA2, 0x9A, 0x03,
9045 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
9046 0x01, 0xA6, 0x96, 0x03,
9047 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
9048 0xA4, 0x03, 0x00, 0xA6,
9049 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
9050 0x07, 0xA6, 0xB2, 0x03,
9051 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
9052 0xA8, 0x98, 0x80, 0x42,
9053 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
9054 0xC0, 0x83, 0x00, 0x33,
9055 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
9056 0xA0, 0x01, 0x12, 0x23,
9057 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
9058 0x80, 0x67, 0x05, 0x23,
9059 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
9060 0x06, 0xA6, 0x0A, 0x04,
9061 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
9062 0xF4, 0x83, 0x20, 0x84,
9063 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
9064 0x83, 0x03, 0x80, 0x63,
9065 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
9066 0x38, 0x04, 0x00, 0x33,
9067 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
9068 0x1D, 0x01, 0x06, 0xCC,
9069 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
9070 0xA2, 0x0D, 0x80, 0x63,
9071 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
9072 0x80, 0x63, 0xA3, 0x01,
9073 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
9074 0x76, 0x04, 0xE0, 0x00,
9075 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
9076 0x00, 0x33, 0x1E, 0x00,
9077 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
9078 0x08, 0x23, 0x22, 0xA3,
9079 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
9080 0xC4, 0x04, 0x42, 0x23,
9081 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
9082 0xF8, 0x88, 0x04, 0x98,
9083 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
9084 0x81, 0x62, 0xE8, 0x81,
9085 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
9086 0x00, 0x33, 0x00, 0x81,
9087 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
9088 0xF8, 0x88, 0x04, 0x23,
9089 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
9090 0xF4, 0x04, 0x00, 0x33,
9091 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9092 0x04, 0x23, 0xA0, 0x01,
9093 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9094 0x00, 0xA3, 0x22, 0x05,
9095 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9096 0x46, 0x97, 0xCD, 0x04,
9097 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9098 0x82, 0x01, 0x34, 0x85,
9099 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9100 0x1D, 0x01, 0x04, 0xD6,
9101 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9102 0x49, 0x00, 0x81, 0x01,
9103 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9104 0x49, 0x04, 0x80, 0x01,
9105 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9106 0x01, 0x23, 0xEA, 0x00,
9107 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9108 0x07, 0xA4, 0xF8, 0x05,
9109 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9110 0xC2, 0x88, 0x04, 0xA0,
9111 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9112 0x00, 0xA2, 0xA4, 0x05,
9113 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9114 0x62, 0x97, 0x04, 0x85,
9115 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9116 0xF4, 0x85, 0x03, 0xA0,
9117 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9118 0xCC, 0x86, 0x07, 0xA0,
9119 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9120 0x80, 0x67, 0x80, 0x63,
9121 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9122 0xF8, 0x88, 0x07, 0x23,
9123 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9124 0x00, 0x63, 0x4A, 0x00,
9125 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9126 0x07, 0x41, 0x83, 0x03,
9127 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9128 0x1D, 0x01, 0x01, 0xD6,
9129 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9130 0x07, 0xA6, 0x7C, 0x05,
9131 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9132 0x52, 0x00, 0x06, 0x61,
9133 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9134 0x00, 0x63, 0x1D, 0x01,
9135 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9136 0x07, 0x41, 0x00, 0x63,
9137 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9138 0xDF, 0x00, 0x06, 0xA6,
9139 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9140 0x00, 0x40, 0xC0, 0x20,
9141 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9142 0x06, 0xA6, 0x94, 0x06,
9143 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9144 0x40, 0x0E, 0x80, 0x63,
9145 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9146 0x80, 0x63, 0x00, 0x43,
9147 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9148 0x80, 0x67, 0x40, 0x0E,
9149 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9150 0x07, 0xA6, 0xD6, 0x06,
9151 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9152 0x0A, 0x2B, 0x07, 0xA6,
9153 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9154 0xF4, 0x06, 0xC0, 0x0E,
9155 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9156 0x81, 0x62, 0x04, 0x01,
9157 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9158 0x8C, 0x06, 0x00, 0x33,
9159 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9160 0x80, 0x63, 0x06, 0xA6,
9161 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9162 0x00, 0x00, 0x80, 0x67,
9163 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9164 0xBF, 0x23, 0x04, 0x61,
9165 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9166 0x00, 0x01, 0xF2, 0x00,
9167 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9168 0x80, 0x05, 0x81, 0x05,
9169 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9170 0x70, 0x00, 0x81, 0x01,
9171 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9172 0x70, 0x00, 0x80, 0x01,
9173 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9174 0xF1, 0x00, 0x70, 0x00,
9175 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9176 0x71, 0x04, 0x70, 0x00,
9177 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9178 0xA3, 0x01, 0xA2, 0x01,
9179 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9180 0xC4, 0x07, 0x00, 0x33,
9181 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9182 0x48, 0x00, 0xB0, 0x01,
9183 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9184 0x00, 0xA2, 0xE4, 0x07,
9185 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9186 0x05, 0x05, 0x00, 0x63,
9187 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9188 0x76, 0x08, 0x80, 0x02,
9189 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9190 0x00, 0x02, 0x00, 0xA0,
9191 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9192 0x00, 0x63, 0xF3, 0x04,
9193 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9194 0x00, 0xA2, 0x44, 0x08,
9195 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9196 0x24, 0x08, 0x04, 0x98,
9197 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9198 0x5A, 0x88, 0x02, 0x01,
9199 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9200 0x00, 0xA3, 0x64, 0x08,
9201 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9202 0x06, 0xA6, 0x76, 0x08,
9203 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9204 0x00, 0x63, 0x38, 0x2B,
9205 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9206 0x05, 0x05, 0xB2, 0x09,
9207 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9208 0x80, 0x32, 0x80, 0x36,
9209 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9210 0x40, 0x36, 0x40, 0x3A,
9211 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9212 0x5D, 0x00, 0xFE, 0xC3,
9213 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9214 0xFF, 0xFD, 0x80, 0x73,
9215 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9216 0xA1, 0x23, 0xA1, 0x01,
9217 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9218 0x80, 0x00, 0x03, 0xC2,
9219 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9220 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009221};
9222
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009223static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9224static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009225
9226#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009227static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9228 INQUIRY,
9229 REQUEST_SENSE,
9230 READ_CAPACITY,
9231 READ_TOC,
9232 MODE_SELECT,
9233 MODE_SENSE,
9234 MODE_SELECT_10,
9235 MODE_SENSE_10,
9236 0xFF,
9237 0xFF,
9238 0xFF,
9239 0xFF,
9240 0xFF,
9241 0xFF,
9242 0xFF,
9243 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009244};
9245
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009246static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009247{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009248 PortAddr iop_base;
9249 ulong last_int_level;
9250 int sta;
9251 int n_q_required;
9252 int disable_syn_offset_one_fix;
9253 int i;
9254 ASC_PADDR addr;
9255 ASC_EXE_CALLBACK asc_exe_callback;
9256 ushort sg_entry_cnt = 0;
9257 ushort sg_entry_cnt_minus_one = 0;
9258 uchar target_ix;
9259 uchar tid_no;
9260 uchar sdtr_data;
9261 uchar extra_bytes;
9262 uchar scsi_cmd;
9263 uchar disable_cmd;
9264 ASC_SG_HEAD *sg_head;
9265 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009266
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009267 iop_base = asc_dvc->iop_base;
9268 sg_head = scsiq->sg_head;
9269 asc_exe_callback = asc_dvc->exe_callback;
9270 if (asc_dvc->err_code != 0)
9271 return (ERR);
9272 if (scsiq == (ASC_SCSI_Q *)0L) {
9273 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9274 return (ERR);
9275 }
9276 scsiq->q1.q_no = 0;
9277 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9278 scsiq->q1.extra_bytes = 0;
9279 }
9280 sta = 0;
9281 target_ix = scsiq->q2.target_ix;
9282 tid_no = ASC_TIX_TO_TID(target_ix);
9283 n_q_required = 1;
9284 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9285 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9286 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9287 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9288 AscMsgOutSDTR(asc_dvc,
9289 asc_dvc->
9290 sdtr_period_tbl[(sdtr_data >> 4) &
9291 (uchar)(asc_dvc->
9292 max_sdtr_index -
9293 1)],
9294 (uchar)(sdtr_data & (uchar)
9295 ASC_SYN_MAX_OFFSET));
9296 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9297 }
9298 }
9299 last_int_level = DvcEnterCritical();
9300 if (asc_dvc->in_critical_cnt != 0) {
9301 DvcLeaveCritical(last_int_level);
9302 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9303 return (ERR);
9304 }
9305 asc_dvc->in_critical_cnt++;
9306 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9307 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9308 asc_dvc->in_critical_cnt--;
9309 DvcLeaveCritical(last_int_level);
9310 return (ERR);
9311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009312#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009313 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9314 asc_dvc->in_critical_cnt--;
9315 DvcLeaveCritical(last_int_level);
9316 return (ERR);
9317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009318#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009319 if (sg_entry_cnt == 1) {
9320 scsiq->q1.data_addr =
9321 (ADV_PADDR)sg_head->sg_list[0].addr;
9322 scsiq->q1.data_cnt =
9323 (ADV_DCNT)sg_head->sg_list[0].bytes;
9324 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9325 }
9326 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9327 }
9328 scsi_cmd = scsiq->cdbptr[0];
9329 disable_syn_offset_one_fix = FALSE;
9330 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9331 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9332 if (scsiq->q1.cntl & QC_SG_HEAD) {
9333 data_cnt = 0;
9334 for (i = 0; i < sg_entry_cnt; i++) {
9335 data_cnt +=
9336 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9337 bytes);
9338 }
9339 } else {
9340 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9341 }
9342 if (data_cnt != 0UL) {
9343 if (data_cnt < 512UL) {
9344 disable_syn_offset_one_fix = TRUE;
9345 } else {
9346 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9347 i++) {
9348 disable_cmd =
9349 _syn_offset_one_disable_cmd[i];
9350 if (disable_cmd == 0xFF) {
9351 break;
9352 }
9353 if (scsi_cmd == disable_cmd) {
9354 disable_syn_offset_one_fix =
9355 TRUE;
9356 break;
9357 }
9358 }
9359 }
9360 }
9361 }
9362 if (disable_syn_offset_one_fix) {
9363 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9364 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9365 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9366 } else {
9367 scsiq->q2.tag_code &= 0x27;
9368 }
9369 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9370 if (asc_dvc->bug_fix_cntl) {
9371 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9372 if ((scsi_cmd == READ_6) ||
9373 (scsi_cmd == READ_10)) {
9374 addr =
9375 (ADV_PADDR)le32_to_cpu(sg_head->
9376 sg_list
9377 [sg_entry_cnt_minus_one].
9378 addr) +
9379 (ADV_DCNT)le32_to_cpu(sg_head->
9380 sg_list
9381 [sg_entry_cnt_minus_one].
9382 bytes);
9383 extra_bytes =
9384 (uchar)((ushort)addr & 0x0003);
9385 if ((extra_bytes != 0)
9386 &&
9387 ((scsiq->q2.
9388 tag_code &
9389 ASC_TAG_FLAG_EXTRA_BYTES)
9390 == 0)) {
9391 scsiq->q2.tag_code |=
9392 ASC_TAG_FLAG_EXTRA_BYTES;
9393 scsiq->q1.extra_bytes =
9394 extra_bytes;
9395 data_cnt =
9396 le32_to_cpu(sg_head->
9397 sg_list
9398 [sg_entry_cnt_minus_one].
9399 bytes);
9400 data_cnt -=
9401 (ASC_DCNT) extra_bytes;
9402 sg_head->
9403 sg_list
9404 [sg_entry_cnt_minus_one].
9405 bytes =
9406 cpu_to_le32(data_cnt);
9407 }
9408 }
9409 }
9410 }
9411 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009412#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009413 /*
9414 * Set the sg_entry_cnt to the maximum possible. The rest of
9415 * the SG elements will be copied when the RISC completes the
9416 * SG elements that fit and halts.
9417 */
9418 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9419 sg_entry_cnt = ASC_MAX_SG_LIST;
9420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009421#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009422 n_q_required = AscSgListToQueue(sg_entry_cnt);
9423 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9424 (uint) n_q_required)
9425 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9426 if ((sta =
9427 AscSendScsiQueue(asc_dvc, scsiq,
9428 n_q_required)) == 1) {
9429 asc_dvc->in_critical_cnt--;
9430 if (asc_exe_callback != 0) {
9431 (*asc_exe_callback) (asc_dvc, scsiq);
9432 }
9433 DvcLeaveCritical(last_int_level);
9434 return (sta);
9435 }
9436 }
9437 } else {
9438 if (asc_dvc->bug_fix_cntl) {
9439 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9440 if ((scsi_cmd == READ_6) ||
9441 (scsi_cmd == READ_10)) {
9442 addr =
9443 le32_to_cpu(scsiq->q1.data_addr) +
9444 le32_to_cpu(scsiq->q1.data_cnt);
9445 extra_bytes =
9446 (uchar)((ushort)addr & 0x0003);
9447 if ((extra_bytes != 0)
9448 &&
9449 ((scsiq->q2.
9450 tag_code &
9451 ASC_TAG_FLAG_EXTRA_BYTES)
9452 == 0)) {
9453 data_cnt =
9454 le32_to_cpu(scsiq->q1.
9455 data_cnt);
9456 if (((ushort)data_cnt & 0x01FF)
9457 == 0) {
9458 scsiq->q2.tag_code |=
9459 ASC_TAG_FLAG_EXTRA_BYTES;
9460 data_cnt -= (ASC_DCNT)
9461 extra_bytes;
9462 scsiq->q1.data_cnt =
9463 cpu_to_le32
9464 (data_cnt);
9465 scsiq->q1.extra_bytes =
9466 extra_bytes;
9467 }
9468 }
9469 }
9470 }
9471 }
9472 n_q_required = 1;
9473 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9474 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9475 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9476 n_q_required)) == 1) {
9477 asc_dvc->in_critical_cnt--;
9478 if (asc_exe_callback != 0) {
9479 (*asc_exe_callback) (asc_dvc, scsiq);
9480 }
9481 DvcLeaveCritical(last_int_level);
9482 return (sta);
9483 }
9484 }
9485 }
9486 asc_dvc->in_critical_cnt--;
9487 DvcLeaveCritical(last_int_level);
9488 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009489}
9490
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009491static int
9492AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009493{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009494 PortAddr iop_base;
9495 uchar free_q_head;
9496 uchar next_qp;
9497 uchar tid_no;
9498 uchar target_ix;
9499 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009500
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009501 iop_base = asc_dvc->iop_base;
9502 target_ix = scsiq->q2.target_ix;
9503 tid_no = ASC_TIX_TO_TID(target_ix);
9504 sta = 0;
9505 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9506 if (n_q_required > 1) {
9507 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9508 free_q_head, (uchar)
9509 (n_q_required)))
9510 != (uchar)ASC_QLINK_END) {
9511 asc_dvc->last_q_shortage = 0;
9512 scsiq->sg_head->queue_cnt = n_q_required - 1;
9513 scsiq->q1.q_no = free_q_head;
9514 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9515 free_q_head)) == 1) {
9516 AscPutVarFreeQHead(iop_base, next_qp);
9517 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9518 asc_dvc->cur_dvc_qng[tid_no]++;
9519 }
9520 return (sta);
9521 }
9522 } else if (n_q_required == 1) {
9523 if ((next_qp = AscAllocFreeQueue(iop_base,
9524 free_q_head)) !=
9525 ASC_QLINK_END) {
9526 scsiq->q1.q_no = free_q_head;
9527 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9528 free_q_head)) == 1) {
9529 AscPutVarFreeQHead(iop_base, next_qp);
9530 asc_dvc->cur_total_qng++;
9531 asc_dvc->cur_dvc_qng[tid_no]++;
9532 }
9533 return (sta);
9534 }
9535 }
9536 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009537}
9538
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009539static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009540{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009541 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009542
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009543 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9544 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9545 n_sg_list_qs++;
9546 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009547}
9548
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009549static uint
9550AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009551{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009552 uint cur_used_qs;
9553 uint cur_free_qs;
9554 ASC_SCSI_BIT_ID_TYPE target_id;
9555 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009556
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009557 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9558 tid_no = ASC_TIX_TO_TID(target_ix);
9559 if ((asc_dvc->unit_not_ready & target_id) ||
9560 (asc_dvc->queue_full_or_busy & target_id)) {
9561 return (0);
9562 }
9563 if (n_qs == 1) {
9564 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9565 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9566 } else {
9567 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9568 (uint) ASC_MIN_FREE_Q;
9569 }
9570 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9571 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9572 if (asc_dvc->cur_dvc_qng[tid_no] >=
9573 asc_dvc->max_dvc_qng[tid_no]) {
9574 return (0);
9575 }
9576 return (cur_free_qs);
9577 }
9578 if (n_qs > 1) {
9579 if ((n_qs > asc_dvc->last_q_shortage)
9580 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9581 asc_dvc->last_q_shortage = n_qs;
9582 }
9583 }
9584 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009585}
9586
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009587static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009588{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009589 ushort q_addr;
9590 uchar tid_no;
9591 uchar sdtr_data;
9592 uchar syn_period_ix;
9593 uchar syn_offset;
9594 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009595
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009596 iop_base = asc_dvc->iop_base;
9597 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9598 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9599 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9600 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9601 syn_period_ix =
9602 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9603 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9604 AscMsgOutSDTR(asc_dvc,
9605 asc_dvc->sdtr_period_tbl[syn_period_ix],
9606 syn_offset);
9607 scsiq->q1.cntl |= QC_MSG_OUT;
9608 }
9609 q_addr = ASC_QNO_TO_QADDR(q_no);
9610 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9611 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9612 }
9613 scsiq->q1.status = QS_FREE;
9614 AscMemWordCopyPtrToLram(iop_base,
9615 q_addr + ASC_SCSIQ_CDB_BEG,
9616 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009617
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009618 DvcPutScsiQ(iop_base,
9619 q_addr + ASC_SCSIQ_CPY_BEG,
9620 (uchar *)&scsiq->q1.cntl,
9621 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9622 AscWriteLramWord(iop_base,
9623 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9624 (ushort)(((ushort)scsiq->q1.
9625 q_no << 8) | (ushort)QS_READY));
9626 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009627}
9628
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009629static int
9630AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009631{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009632 int sta;
9633 int i;
9634 ASC_SG_HEAD *sg_head;
9635 ASC_SG_LIST_Q scsi_sg_q;
9636 ASC_DCNT saved_data_addr;
9637 ASC_DCNT saved_data_cnt;
9638 PortAddr iop_base;
9639 ushort sg_list_dwords;
9640 ushort sg_index;
9641 ushort sg_entry_cnt;
9642 ushort q_addr;
9643 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009644
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009645 iop_base = asc_dvc->iop_base;
9646 sg_head = scsiq->sg_head;
9647 saved_data_addr = scsiq->q1.data_addr;
9648 saved_data_cnt = scsiq->q1.data_cnt;
9649 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9650 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009651#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009652 /*
9653 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9654 * then not all SG elements will fit in the allocated queues.
9655 * The rest of the SG elements will be copied when the RISC
9656 * completes the SG elements that fit and halts.
9657 */
9658 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9659 /*
9660 * Set sg_entry_cnt to be the number of SG elements that
9661 * will fit in the allocated SG queues. It is minus 1, because
9662 * the first SG element is handled above. ASC_MAX_SG_LIST is
9663 * already inflated by 1 to account for this. For example it
9664 * may be 50 which is 1 + 7 queues * 7 SG elements.
9665 */
9666 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009667
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009668 /*
9669 * Keep track of remaining number of SG elements that will
9670 * need to be handled from a_isr.c.
9671 */
9672 scsiq->remain_sg_entry_cnt =
9673 sg_head->entry_cnt - ASC_MAX_SG_LIST;
9674 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009675#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009676 /*
9677 * Set sg_entry_cnt to be the number of SG elements that
9678 * will fit in the allocated SG queues. It is minus 1, because
9679 * the first SG element is handled above.
9680 */
9681 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009682#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009684#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009685 if (sg_entry_cnt != 0) {
9686 scsiq->q1.cntl |= QC_SG_HEAD;
9687 q_addr = ASC_QNO_TO_QADDR(q_no);
9688 sg_index = 1;
9689 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
9690 scsi_sg_q.sg_head_qp = q_no;
9691 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
9692 for (i = 0; i < sg_head->queue_cnt; i++) {
9693 scsi_sg_q.seq_no = i + 1;
9694 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
9695 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
9696 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
9697 if (i == 0) {
9698 scsi_sg_q.sg_list_cnt =
9699 ASC_SG_LIST_PER_Q;
9700 scsi_sg_q.sg_cur_list_cnt =
9701 ASC_SG_LIST_PER_Q;
9702 } else {
9703 scsi_sg_q.sg_list_cnt =
9704 ASC_SG_LIST_PER_Q - 1;
9705 scsi_sg_q.sg_cur_list_cnt =
9706 ASC_SG_LIST_PER_Q - 1;
9707 }
9708 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009709#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009710 /*
9711 * This is the last SG queue in the list of
9712 * allocated SG queues. If there are more
9713 * SG elements than will fit in the allocated
9714 * queues, then set the QCSG_SG_XFER_MORE flag.
9715 */
9716 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9717 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
9718 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009719#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009720 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009721#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009722 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009723#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009724 sg_list_dwords = sg_entry_cnt << 1;
9725 if (i == 0) {
9726 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
9727 scsi_sg_q.sg_cur_list_cnt =
9728 sg_entry_cnt;
9729 } else {
9730 scsi_sg_q.sg_list_cnt =
9731 sg_entry_cnt - 1;
9732 scsi_sg_q.sg_cur_list_cnt =
9733 sg_entry_cnt - 1;
9734 }
9735 sg_entry_cnt = 0;
9736 }
9737 next_qp = AscReadLramByte(iop_base,
9738 (ushort)(q_addr +
9739 ASC_SCSIQ_B_FWD));
9740 scsi_sg_q.q_no = next_qp;
9741 q_addr = ASC_QNO_TO_QADDR(next_qp);
9742 AscMemWordCopyPtrToLram(iop_base,
9743 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
9744 (uchar *)&scsi_sg_q,
9745 sizeof(ASC_SG_LIST_Q) >> 1);
9746 AscMemDWordCopyPtrToLram(iop_base,
9747 q_addr + ASC_SGQ_LIST_BEG,
9748 (uchar *)&sg_head->
9749 sg_list[sg_index],
9750 sg_list_dwords);
9751 sg_index += ASC_SG_LIST_PER_Q;
9752 scsiq->next_sg_index = sg_index;
9753 }
9754 } else {
9755 scsiq->q1.cntl &= ~QC_SG_HEAD;
9756 }
9757 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
9758 scsiq->q1.data_addr = saved_data_addr;
9759 scsiq->q1.data_cnt = saved_data_cnt;
9760 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009761}
9762
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009763static int
9764AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009765{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009766 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009767
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009768 if (AscHostReqRiscHalt(iop_base)) {
9769 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9770 AscStartChip(iop_base);
9771 return (sta);
9772 }
9773 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009774}
9775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009776static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009777{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009778 ASC_SCSI_BIT_ID_TYPE org_id;
9779 int i;
9780 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009781
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009782 AscSetBank(iop_base, 1);
9783 org_id = AscReadChipDvcID(iop_base);
9784 for (i = 0; i <= ASC_MAX_TID; i++) {
9785 if (org_id == (0x01 << i))
9786 break;
9787 }
9788 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
9789 AscWriteChipDvcID(iop_base, id);
9790 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
9791 AscSetBank(iop_base, 0);
9792 AscSetChipSyn(iop_base, sdtr_data);
9793 if (AscGetChipSyn(iop_base) != sdtr_data) {
9794 sta = FALSE;
9795 }
9796 } else {
9797 sta = FALSE;
9798 }
9799 AscSetBank(iop_base, 1);
9800 AscWriteChipDvcID(iop_base, org_id);
9801 AscSetBank(iop_base, 0);
9802 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009803}
9804
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009805static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009806{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009807 uchar i;
9808 ushort s_addr;
9809 PortAddr iop_base;
9810 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009811
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009812 iop_base = asc_dvc->iop_base;
9813 warn_code = 0;
9814 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
9815 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
9816 64) >> 1)
9817 );
9818 i = ASC_MIN_ACTIVE_QNO;
9819 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
9820 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9821 (uchar)(i + 1));
9822 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9823 (uchar)(asc_dvc->max_total_qng));
9824 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9825 (uchar)i);
9826 i++;
9827 s_addr += ASC_QBLK_SIZE;
9828 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
9829 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9830 (uchar)(i + 1));
9831 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9832 (uchar)(i - 1));
9833 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9834 (uchar)i);
9835 }
9836 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9837 (uchar)ASC_QLINK_END);
9838 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9839 (uchar)(asc_dvc->max_total_qng - 1));
9840 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9841 (uchar)asc_dvc->max_total_qng);
9842 i++;
9843 s_addr += ASC_QBLK_SIZE;
9844 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
9845 i++, s_addr += ASC_QBLK_SIZE) {
9846 AscWriteLramByte(iop_base,
9847 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
9848 AscWriteLramByte(iop_base,
9849 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
9850 AscWriteLramByte(iop_base,
9851 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
9852 }
9853 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009854}
9855
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009856static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009857{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009858 PortAddr iop_base;
9859 int i;
9860 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009861
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009862 iop_base = asc_dvc->iop_base;
9863 AscPutRiscVarFreeQHead(iop_base, 1);
9864 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9865 AscPutVarFreeQHead(iop_base, 1);
9866 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9867 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
9868 (uchar)((int)asc_dvc->max_total_qng + 1));
9869 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
9870 (uchar)((int)asc_dvc->max_total_qng + 2));
9871 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
9872 asc_dvc->max_total_qng);
9873 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
9874 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
9875 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
9876 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
9877 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
9878 AscPutQDoneInProgress(iop_base, 0);
9879 lram_addr = ASC_QADR_BEG;
9880 for (i = 0; i < 32; i++, lram_addr += 2) {
9881 AscWriteLramWord(iop_base, lram_addr, 0);
9882 }
9883 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009884}
9885
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009886static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009887{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009888 if (asc_dvc->err_code == 0) {
9889 asc_dvc->err_code = err_code;
9890 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
9891 err_code);
9892 }
9893 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009894}
9895
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009896static uchar
9897AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009898{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009899 EXT_MSG sdtr_buf;
9900 uchar sdtr_period_index;
9901 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009902
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009903 iop_base = asc_dvc->iop_base;
9904 sdtr_buf.msg_type = MS_EXTEND;
9905 sdtr_buf.msg_len = MS_SDTR_LEN;
9906 sdtr_buf.msg_req = MS_SDTR_CODE;
9907 sdtr_buf.xfer_period = sdtr_period;
9908 sdtr_offset &= ASC_SYN_MAX_OFFSET;
9909 sdtr_buf.req_ack_offset = sdtr_offset;
9910 if ((sdtr_period_index =
9911 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
9912 asc_dvc->max_sdtr_index) {
9913 AscMemWordCopyPtrToLram(iop_base,
9914 ASCV_MSGOUT_BEG,
9915 (uchar *)&sdtr_buf,
9916 sizeof(EXT_MSG) >> 1);
9917 return ((sdtr_period_index << 4) | sdtr_offset);
9918 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009919
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009920 sdtr_buf.req_ack_offset = 0;
9921 AscMemWordCopyPtrToLram(iop_base,
9922 ASCV_MSGOUT_BEG,
9923 (uchar *)&sdtr_buf,
9924 sizeof(EXT_MSG) >> 1);
9925 return (0);
9926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009927}
9928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009929static uchar
9930AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009931{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009932 uchar byte;
9933 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009934
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009935 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
9936 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
9937 ) {
9938 return (0xFF);
9939 }
9940 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
9941 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009942}
9943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009944static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009945{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009946 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9947 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
9948 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009949}
9950
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009951static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009952{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009953 uchar *period_table;
9954 int max_index;
9955 int min_index;
9956 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009957
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009958 period_table = asc_dvc->sdtr_period_tbl;
9959 max_index = (int)asc_dvc->max_sdtr_index;
9960 min_index = (int)asc_dvc->host_init_sdtr_index;
9961 if ((syn_time <= period_table[max_index])) {
9962 for (i = min_index; i < (max_index - 1); i++) {
9963 if (syn_time <= period_table[i]) {
9964 return ((uchar)i);
9965 }
9966 }
9967 return ((uchar)max_index);
9968 } else {
9969 return ((uchar)(max_index + 1));
9970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009971}
9972
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009973static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009974{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009975 ushort q_addr;
9976 uchar next_qp;
9977 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009978
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009979 q_addr = ASC_QNO_TO_QADDR(free_q_head);
9980 q_status = (uchar)AscReadLramByte(iop_base,
9981 (ushort)(q_addr +
9982 ASC_SCSIQ_B_STATUS));
9983 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
9984 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
9985 return (next_qp);
9986 }
9987 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009988}
9989
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009990static uchar
9991AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009992{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009993 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009994
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009995 for (i = 0; i < n_free_q; i++) {
9996 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
9997 == ASC_QLINK_END) {
9998 return (ASC_QLINK_END);
9999 }
10000 }
10001 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010002}
10003
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010004static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010005{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010006 int count = 0;
10007 int sta = 0;
10008 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010009
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010010 if (AscIsChipHalted(iop_base))
10011 return (1);
10012 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
10013 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10014 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
10015 do {
10016 if (AscIsChipHalted(iop_base)) {
10017 sta = 1;
10018 break;
10019 }
10020 DvcSleepMilliSecond(100);
10021 } while (count++ < 20);
10022 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
10023 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010024}
10025
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010026static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010027{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010028 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010029
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010030 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
10031 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10032 ASC_STOP_REQ_RISC_STOP);
10033 do {
10034 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
10035 ASC_STOP_ACK_RISC_STOP) {
10036 return (1);
10037 }
10038 DvcSleepMilliSecond(100);
10039 } while (count++ < 20);
10040 }
10041 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010042}
10043
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010044static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010045{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010046 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010047}
10048
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010049static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010050{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010051 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010052}
10053
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010054static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010055{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010056 AscSetChipControl(iop_base, 0);
10057 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10058 return (0);
10059 }
10060 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010061}
10062
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010063static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010064{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010065 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010066
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010067 cc_val =
10068 AscGetChipControl(iop_base) &
10069 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
10070 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
10071 AscSetChipIH(iop_base, INS_HALT);
10072 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10073 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
10074 return (0);
10075 }
10076 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010077}
10078
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010079static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010080{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010081 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10082 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
10083 return (1);
10084 }
10085 }
10086 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010087}
10088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010089static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010090{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010091 AscSetBank(iop_base, 1);
10092 AscWriteChipIH(iop_base, ins_code);
10093 AscSetBank(iop_base, 0);
10094 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010095}
10096
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010097static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010098{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010099 uchar host_flag;
10100 uchar risc_flag;
10101 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010102
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010103 loop = 0;
10104 do {
10105 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10106 if (loop++ > 0x7FFF) {
10107 break;
10108 }
10109 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10110 host_flag =
10111 AscReadLramByte(iop_base,
10112 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10113 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10114 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10115 AscSetChipStatus(iop_base, CIW_INT_ACK);
10116 loop = 0;
10117 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10118 AscSetChipStatus(iop_base, CIW_INT_ACK);
10119 if (loop++ > 3) {
10120 break;
10121 }
10122 }
10123 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10124 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010125}
10126
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010127static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010128{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010129 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010130
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010131 cfg = AscGetChipCfgLsw(iop_base);
10132 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10133 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010134}
10135
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010136static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010137{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010138 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010139
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010140 cfg = AscGetChipCfgLsw(iop_base);
10141 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10142 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010143}
10144
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010145static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010146{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010147 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010148
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010149 val = AscGetChipControl(iop_base) &
10150 (~
10151 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10152 CC_CHIP_RESET));
10153 if (bank == 1) {
10154 val |= CC_BANK_ONE;
10155 } else if (bank == 2) {
10156 val |= CC_DIAG | CC_BANK_ONE;
10157 } else {
10158 val &= ~CC_BANK_ONE;
10159 }
10160 AscSetChipControl(iop_base, val);
10161 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010162}
10163
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010164static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010165{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010166 PortAddr iop_base;
10167 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010168
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010169 iop_base = asc_dvc->iop_base;
10170 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10171 && (i-- > 0)) {
10172 DvcSleepMilliSecond(100);
10173 }
10174 AscStopChip(iop_base);
10175 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10176 DvcDelayNanoSecond(asc_dvc, 60000);
10177 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10178 AscSetChipIH(iop_base, INS_HALT);
10179 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10180 AscSetChipControl(iop_base, CC_HALT);
10181 DvcSleepMilliSecond(200);
10182 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10183 AscSetChipStatus(iop_base, 0);
10184 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010185}
10186
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010187static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010188{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010189 if (bus_type & ASC_IS_ISA)
10190 return (ASC_MAX_ISA_DMA_COUNT);
10191 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10192 return (ASC_MAX_VL_DMA_COUNT);
10193 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010194}
10195
10196#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010197static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010198{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010199 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010200
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010201 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10202 if (channel == 0x03)
10203 return (0);
10204 else if (channel == 0x00)
10205 return (7);
10206 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010207}
10208
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010209static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010210{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010211 ushort cfg_lsw;
10212 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010213
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010214 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10215 if (dma_channel == 7)
10216 value = 0x00;
10217 else
10218 value = dma_channel - 4;
10219 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10220 cfg_lsw |= value;
10221 AscSetChipCfgLsw(iop_base, cfg_lsw);
10222 return (AscGetIsaDmaChannel(iop_base));
10223 }
10224 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010225}
10226
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010227static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010228{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010229 speed_value &= 0x07;
10230 AscSetBank(iop_base, 1);
10231 AscWriteChipDmaSpeed(iop_base, speed_value);
10232 AscSetBank(iop_base, 0);
10233 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010234}
10235
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010236static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010237{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010238 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010239
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010240 AscSetBank(iop_base, 1);
10241 speed_value = AscReadChipDmaSpeed(iop_base);
10242 speed_value &= 0x07;
10243 AscSetBank(iop_base, 0);
10244 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010245}
10246#endif /* CONFIG_ISA */
10247
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010248static ushort __devinit AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010249{
Matthew Wilcox9649af32007-07-26 21:51:47 -060010250 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010251
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010252 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -060010253 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010254 return (UW_ERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010255
Matthew Wilcox9649af32007-07-26 21:51:47 -060010256 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010257 warn_code |= AscInitAscDvcVar(asc_dvc);
10258 warn_code |= AscInitFromEEP(asc_dvc);
10259 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
10260 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
10261 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
10262 }
10263 } else {
10264 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10265 }
10266 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010267}
10268
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010269static ushort __devinit AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010270{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010271 ushort warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010272
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010273 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10274 if (asc_dvc->err_code != 0)
10275 return (UW_ERR);
10276 if (AscFindSignature(asc_dvc->iop_base)) {
10277 warn_code |= AscInitFromAscDvcVar(asc_dvc);
10278 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10279 } else {
10280 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10281 }
10282 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010283}
10284
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010285static ushort __devinit AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010286{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010287 PortAddr iop_base;
10288 ushort cfg_msw;
10289 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010290
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010291 iop_base = asc_dvc->iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010292 warn_code = 0;
10293 cfg_msw = AscGetChipCfgMsw(iop_base);
10294 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10295 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10296 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10297 AscSetChipCfgMsw(iop_base, cfg_msw);
10298 }
10299 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10300 asc_dvc->cfg->cmd_qng_enabled) {
10301 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10302 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10303 }
10304 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10305 warn_code |= ASC_WARN_AUTO_CONFIG;
10306 }
10307 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10308 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10309 != asc_dvc->irq_no) {
10310 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10311 }
10312 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010313#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010314 if (asc_dvc->bus_type & ASC_IS_PCI) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010315 struct pci_dev *pdev = to_pci_dev(asc_dvc->cfg->dev);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010316 cfg_msw &= 0xFFC0;
10317 AscSetChipCfgMsw(iop_base, cfg_msw);
10318 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10319 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010320 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
10321 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010322 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10323 asc_dvc->bug_fix_cntl |=
10324 ASC_BUG_FIX_ASYN_USE_SYN;
10325 }
10326 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010327 } else
10328#endif /* CONFIG_PCI */
10329 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010330 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10331 == ASC_CHIP_VER_ASYN_BUG) {
10332 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10333 }
10334 }
10335 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10336 asc_dvc->cfg->chip_scsi_id) {
10337 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010339#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010340 if (asc_dvc->bus_type & ASC_IS_ISA) {
10341 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10342 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10343 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010344#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010345 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010346}
10347
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010348static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010349{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010350 ushort warn_code;
10351 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010352
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010353 iop_base = asc_dvc->iop_base;
10354 warn_code = 0;
10355 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10356 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10357 AscResetChipAndScsiBus(asc_dvc);
10358 DvcSleepMilliSecond((ASC_DCNT)
10359 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10360 }
10361 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10362 if (asc_dvc->err_code != 0)
10363 return (UW_ERR);
10364 if (!AscFindSignature(asc_dvc->iop_base)) {
10365 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10366 return (warn_code);
10367 }
10368 AscDisableInterrupt(iop_base);
10369 warn_code |= AscInitLram(asc_dvc);
10370 if (asc_dvc->err_code != 0)
10371 return (UW_ERR);
10372 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10373 (ulong)_asc_mcode_chksum);
10374 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10375 _asc_mcode_size) != _asc_mcode_chksum) {
10376 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10377 return (warn_code);
10378 }
10379 warn_code |= AscInitMicroCodeVar(asc_dvc);
10380 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10381 AscEnableInterrupt(iop_base);
10382 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010383}
10384
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010385static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010386{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010387 int i;
10388 PortAddr iop_base;
10389 ushort warn_code;
10390 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010391
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010392 iop_base = asc_dvc->iop_base;
10393 warn_code = 0;
10394 asc_dvc->err_code = 0;
10395 if ((asc_dvc->bus_type &
10396 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10397 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10398 }
10399 AscSetChipControl(iop_base, CC_HALT);
10400 AscSetChipStatus(iop_base, 0);
10401 asc_dvc->bug_fix_cntl = 0;
10402 asc_dvc->pci_fix_asyn_xfer = 0;
10403 asc_dvc->pci_fix_asyn_xfer_always = 0;
10404 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10405 asc_dvc->sdtr_done = 0;
10406 asc_dvc->cur_total_qng = 0;
10407 asc_dvc->is_in_int = 0;
10408 asc_dvc->in_critical_cnt = 0;
10409 asc_dvc->last_q_shortage = 0;
10410 asc_dvc->use_tagged_qng = 0;
10411 asc_dvc->no_scam = 0;
10412 asc_dvc->unit_not_ready = 0;
10413 asc_dvc->queue_full_or_busy = 0;
10414 asc_dvc->redo_scam = 0;
10415 asc_dvc->res2 = 0;
10416 asc_dvc->host_init_sdtr_index = 0;
10417 asc_dvc->cfg->can_tagged_qng = 0;
10418 asc_dvc->cfg->cmd_qng_enabled = 0;
10419 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10420 asc_dvc->init_sdtr = 0;
10421 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10422 asc_dvc->scsi_reset_wait = 3;
10423 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10424 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10425 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10426 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10427 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10428 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10429 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10430 ASC_LIB_VERSION_MINOR;
10431 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10432 asc_dvc->cfg->chip_version = chip_version;
10433 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10434 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10435 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10436 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10437 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10438 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10439 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10440 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10441 asc_dvc->max_sdtr_index = 7;
10442 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10443 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10444 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10445 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10446 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10447 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10448 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10449 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10450 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10451 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10452 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10453 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10454 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10455 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10456 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10457 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10458 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10459 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10460 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10461 asc_dvc->max_sdtr_index = 15;
10462 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10463 AscSetExtraControl(iop_base,
10464 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10465 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10466 AscSetExtraControl(iop_base,
10467 (SEC_ACTIVE_NEGATE |
10468 SEC_ENABLE_FILTER));
10469 }
10470 }
10471 if (asc_dvc->bus_type == ASC_IS_PCI) {
10472 AscSetExtraControl(iop_base,
10473 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010475
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010476 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
10477 if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
10478 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10479 asc_dvc->bus_type = ASC_IS_ISAPNP;
10480 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010481#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010482 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
10483 asc_dvc->cfg->isa_dma_channel =
10484 (uchar)AscGetIsaDmaChannel(iop_base);
10485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010486#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010487 for (i = 0; i <= ASC_MAX_TID; i++) {
10488 asc_dvc->cur_dvc_qng[i] = 0;
10489 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10490 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10491 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10492 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10493 }
10494 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010495}
10496
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010497static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010498{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010499 ASCEEP_CONFIG eep_config_buf;
10500 ASCEEP_CONFIG *eep_config;
10501 PortAddr iop_base;
10502 ushort chksum;
10503 ushort warn_code;
10504 ushort cfg_msw, cfg_lsw;
10505 int i;
10506 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010507
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010508 iop_base = asc_dvc->iop_base;
10509 warn_code = 0;
10510 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10511 AscStopQueueExe(iop_base);
10512 if ((AscStopChip(iop_base) == FALSE) ||
10513 (AscGetChipScsiCtrl(iop_base) != 0)) {
10514 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10515 AscResetChipAndScsiBus(asc_dvc);
10516 DvcSleepMilliSecond((ASC_DCNT)
10517 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10518 }
10519 if (AscIsChipHalted(iop_base) == FALSE) {
10520 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10521 return (warn_code);
10522 }
10523 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10524 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10525 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10526 return (warn_code);
10527 }
10528 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10529 cfg_msw = AscGetChipCfgMsw(iop_base);
10530 cfg_lsw = AscGetChipCfgLsw(iop_base);
10531 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10532 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10533 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10534 AscSetChipCfgMsw(iop_base, cfg_msw);
10535 }
10536 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
10537 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
10538 if (chksum == 0) {
10539 chksum = 0xaa55;
10540 }
10541 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10542 warn_code |= ASC_WARN_AUTO_CONFIG;
10543 if (asc_dvc->cfg->chip_version == 3) {
10544 if (eep_config->cfg_lsw != cfg_lsw) {
10545 warn_code |= ASC_WARN_EEPROM_RECOVER;
10546 eep_config->cfg_lsw =
10547 AscGetChipCfgLsw(iop_base);
10548 }
10549 if (eep_config->cfg_msw != cfg_msw) {
10550 warn_code |= ASC_WARN_EEPROM_RECOVER;
10551 eep_config->cfg_msw =
10552 AscGetChipCfgMsw(iop_base);
10553 }
10554 }
10555 }
10556 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
10557 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
10558 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
10559 eep_config->chksum);
10560 if (chksum != eep_config->chksum) {
10561 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
10562 ASC_CHIP_VER_PCI_ULTRA_3050) {
10563 ASC_DBG(1,
10564 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
10565 eep_config->init_sdtr = 0xFF;
10566 eep_config->disc_enable = 0xFF;
10567 eep_config->start_motor = 0xFF;
10568 eep_config->use_cmd_qng = 0;
10569 eep_config->max_total_qng = 0xF0;
10570 eep_config->max_tag_qng = 0x20;
10571 eep_config->cntl = 0xBFFF;
10572 ASC_EEP_SET_CHIP_ID(eep_config, 7);
10573 eep_config->no_scam = 0;
10574 eep_config->adapter_info[0] = 0;
10575 eep_config->adapter_info[1] = 0;
10576 eep_config->adapter_info[2] = 0;
10577 eep_config->adapter_info[3] = 0;
10578 eep_config->adapter_info[4] = 0;
10579 /* Indicate EEPROM-less board. */
10580 eep_config->adapter_info[5] = 0xBB;
10581 } else {
10582 ASC_PRINT
10583 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
10584 write_eep = 1;
10585 warn_code |= ASC_WARN_EEPROM_CHKSUM;
10586 }
10587 }
10588 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
10589 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
10590 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
10591 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
10592 asc_dvc->start_motor = eep_config->start_motor;
10593 asc_dvc->dvc_cntl = eep_config->cntl;
10594 asc_dvc->no_scam = eep_config->no_scam;
10595 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
10596 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
10597 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
10598 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
10599 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
10600 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
10601 if (!AscTestExternalLram(asc_dvc)) {
10602 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
10603 ASC_IS_PCI_ULTRA)) {
10604 eep_config->max_total_qng =
10605 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
10606 eep_config->max_tag_qng =
10607 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
10608 } else {
10609 eep_config->cfg_msw |= 0x0800;
10610 cfg_msw |= 0x0800;
10611 AscSetChipCfgMsw(iop_base, cfg_msw);
10612 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
10613 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
10614 }
10615 } else {
10616 }
10617 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
10618 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
10619 }
10620 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
10621 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
10622 }
10623 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
10624 eep_config->max_tag_qng = eep_config->max_total_qng;
10625 }
10626 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
10627 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
10628 }
10629 asc_dvc->max_total_qng = eep_config->max_total_qng;
10630 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
10631 eep_config->use_cmd_qng) {
10632 eep_config->disc_enable = eep_config->use_cmd_qng;
10633 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10634 }
10635 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
10636 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
10637 }
10638 ASC_EEP_SET_CHIP_ID(eep_config,
10639 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
10640 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
10641 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
10642 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
10643 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
10644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010645
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010646 for (i = 0; i <= ASC_MAX_TID; i++) {
10647 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
10648 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
10649 asc_dvc->cfg->sdtr_period_offset[i] =
10650 (uchar)(ASC_DEF_SDTR_OFFSET |
10651 (asc_dvc->host_init_sdtr_index << 4));
10652 }
10653 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
10654 if (write_eep) {
10655 if ((i =
10656 AscSetEEPConfig(iop_base, eep_config,
10657 asc_dvc->bus_type)) != 0) {
10658 ASC_PRINT1
10659 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
10660 i);
10661 } else {
10662 ASC_PRINT
10663 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
10664 }
10665 }
10666 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010667}
10668
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010669static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010670{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010671 int i;
10672 ushort warn_code;
10673 PortAddr iop_base;
10674 ASC_PADDR phy_addr;
10675 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010676
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010677 iop_base = asc_dvc->iop_base;
10678 warn_code = 0;
10679 for (i = 0; i <= ASC_MAX_TID; i++) {
10680 AscPutMCodeInitSDTRAtID(iop_base, i,
10681 asc_dvc->cfg->sdtr_period_offset[i]
10682 );
10683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010684
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010685 AscInitQLinkVar(asc_dvc);
10686 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
10687 asc_dvc->cfg->disc_enable);
10688 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
10689 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010690
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010691 /* Align overrun buffer on an 8 byte boundary. */
10692 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
10693 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
10694 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
10695 (uchar *)&phy_addr, 1);
10696 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
10697 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
10698 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010699
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010700 asc_dvc->cfg->mcode_date =
10701 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
10702 asc_dvc->cfg->mcode_version =
10703 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010704
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010705 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10706 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10707 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10708 return (warn_code);
10709 }
10710 if (AscStartChip(iop_base) != 1) {
10711 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10712 return (warn_code);
10713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010714
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010715 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010716}
10717
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010718static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010719{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010720 PortAddr iop_base;
10721 ushort q_addr;
10722 ushort saved_word;
10723 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010724
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010725 iop_base = asc_dvc->iop_base;
10726 sta = 0;
10727 q_addr = ASC_QNO_TO_QADDR(241);
10728 saved_word = AscReadLramWord(iop_base, q_addr);
10729 AscSetChipLramAddr(iop_base, q_addr);
10730 AscSetChipLramData(iop_base, 0x55AA);
10731 DvcSleepMilliSecond(10);
10732 AscSetChipLramAddr(iop_base, q_addr);
10733 if (AscGetChipLramData(iop_base) == 0x55AA) {
10734 sta = 1;
10735 AscWriteLramWord(iop_base, q_addr, saved_word);
10736 }
10737 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010738}
10739
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010740static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010741{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010742 uchar read_back;
10743 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010744
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010745 retry = 0;
10746 while (TRUE) {
10747 AscSetChipEEPCmd(iop_base, cmd_reg);
10748 DvcSleepMilliSecond(1);
10749 read_back = AscGetChipEEPCmd(iop_base);
10750 if (read_back == cmd_reg) {
10751 return (1);
10752 }
10753 if (retry++ > ASC_EEP_MAX_RETRY) {
10754 return (0);
10755 }
10756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010757}
10758
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010759static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010760{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010761 ushort read_back;
10762 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010763
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010764 retry = 0;
10765 while (TRUE) {
10766 AscSetChipEEPData(iop_base, data_reg);
10767 DvcSleepMilliSecond(1);
10768 read_back = AscGetChipEEPData(iop_base);
10769 if (read_back == data_reg) {
10770 return (1);
10771 }
10772 if (retry++ > ASC_EEP_MAX_RETRY) {
10773 return (0);
10774 }
10775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010776}
10777
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010778static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010779{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010780 DvcSleepMilliSecond(1);
10781 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010782}
10783
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010784static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010785{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010786 DvcSleepMilliSecond(20);
10787 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010788}
10789
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010790static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010791{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010792 ushort read_wval;
10793 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010794
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010795 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10796 AscWaitEEPRead();
10797 cmd_reg = addr | ASC_EEP_CMD_READ;
10798 AscWriteEEPCmdReg(iop_base, cmd_reg);
10799 AscWaitEEPRead();
10800 read_wval = AscGetChipEEPData(iop_base);
10801 AscWaitEEPRead();
10802 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010803}
10804
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010805static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010806AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010807{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010808 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010809
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010810 read_wval = AscReadEEPWord(iop_base, addr);
10811 if (read_wval != word_val) {
10812 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
10813 AscWaitEEPRead();
10814 AscWriteEEPDataReg(iop_base, word_val);
10815 AscWaitEEPRead();
10816 AscWriteEEPCmdReg(iop_base,
10817 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
10818 AscWaitEEPWrite();
10819 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10820 AscWaitEEPRead();
10821 return (AscReadEEPWord(iop_base, addr));
10822 }
10823 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010824}
10825
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010826static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010827AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010828{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010829 ushort wval;
10830 ushort sum;
10831 ushort *wbuf;
10832 int cfg_beg;
10833 int cfg_end;
10834 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
10835 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010836
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010837 wbuf = (ushort *)cfg_buf;
10838 sum = 0;
10839 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
10840 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10841 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10842 sum += *wbuf;
10843 }
10844 if (bus_type & ASC_IS_VL) {
10845 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10846 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10847 } else {
10848 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10849 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10850 }
10851 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10852 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
10853 if (s_addr <= uchar_end_in_config) {
10854 /*
10855 * Swap all char fields - must unswap bytes already swapped
10856 * by AscReadEEPWord().
10857 */
10858 *wbuf = le16_to_cpu(wval);
10859 } else {
10860 /* Don't swap word field at the end - cntl field. */
10861 *wbuf = wval;
10862 }
10863 sum += wval; /* Checksum treats all EEPROM data as words. */
10864 }
10865 /*
10866 * Read the checksum word which will be compared against 'sum'
10867 * by the caller. Word field already swapped.
10868 */
10869 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10870 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010871}
10872
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010873static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010874AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010875{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010876 int n_error;
10877 ushort *wbuf;
10878 ushort word;
10879 ushort sum;
10880 int s_addr;
10881 int cfg_beg;
10882 int cfg_end;
10883 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010884
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010885 wbuf = (ushort *)cfg_buf;
10886 n_error = 0;
10887 sum = 0;
10888 /* Write two config words; AscWriteEEPWord() will swap bytes. */
10889 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10890 sum += *wbuf;
10891 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10892 n_error++;
10893 }
10894 }
10895 if (bus_type & ASC_IS_VL) {
10896 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10897 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10898 } else {
10899 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10900 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10901 }
10902 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10903 if (s_addr <= uchar_end_in_config) {
10904 /*
10905 * This is a char field. Swap char fields before they are
10906 * swapped again by AscWriteEEPWord().
10907 */
10908 word = cpu_to_le16(*wbuf);
10909 if (word !=
10910 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
10911 n_error++;
10912 }
10913 } else {
10914 /* Don't swap word field at the end - cntl field. */
10915 if (*wbuf !=
10916 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10917 n_error++;
10918 }
10919 }
10920 sum += *wbuf; /* Checksum calculated from word values. */
10921 }
10922 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
10923 *wbuf = sum;
10924 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
10925 n_error++;
10926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010927
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010928 /* Read EEPROM back again. */
10929 wbuf = (ushort *)cfg_buf;
10930 /*
10931 * Read two config words; Byte-swapping done by AscReadEEPWord().
10932 */
10933 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10934 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
10935 n_error++;
10936 }
10937 }
10938 if (bus_type & ASC_IS_VL) {
10939 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10940 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10941 } else {
10942 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10943 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10944 }
10945 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10946 if (s_addr <= uchar_end_in_config) {
10947 /*
10948 * Swap all char fields. Must unswap bytes already swapped
10949 * by AscReadEEPWord().
10950 */
10951 word =
10952 le16_to_cpu(AscReadEEPWord
10953 (iop_base, (uchar)s_addr));
10954 } else {
10955 /* Don't swap word field at the end - cntl field. */
10956 word = AscReadEEPWord(iop_base, (uchar)s_addr);
10957 }
10958 if (*wbuf != word) {
10959 n_error++;
10960 }
10961 }
10962 /* Read checksum; Byte swapping not needed. */
10963 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
10964 n_error++;
10965 }
10966 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010967}
10968
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010969static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010970AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010971{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010972 int retry;
10973 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010974
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010975 retry = 0;
10976 while (TRUE) {
10977 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
10978 bus_type)) == 0) {
10979 break;
10980 }
10981 if (++retry > ASC_EEP_MAX_RETRY) {
10982 break;
10983 }
10984 }
10985 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010986}
10987
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010988static void
10989AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010990{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010991 uchar dvc_type;
10992 ASC_SCSI_BIT_ID_TYPE tid_bits;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010993
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010994 dvc_type = ASC_INQ_DVC_TYPE(inq);
10995 tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010996
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010997 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
10998 if (!(asc_dvc->init_sdtr & tid_bits)) {
10999 if ((dvc_type == TYPE_ROM) &&
Matthew Wilcoxce3a7f12007-07-26 11:39:17 -040011000 (strncmp(inq->vendor_id, "HP ", 3) == 0)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011001 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
11002 }
11003 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
11004 if ((dvc_type == TYPE_PROCESSOR) ||
11005 (dvc_type == TYPE_SCANNER) ||
11006 (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) {
11007 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
11008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011009
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011010 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
11011 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
11012 tid_no,
11013 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
11014 }
11015 }
11016 }
11017 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011018}
11019
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011020static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011021{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011022 if ((inq->add_len >= 32) &&
Matthew Wilcoxce3a7f12007-07-26 11:39:17 -040011023 (strncmp(inq->vendor_id, "QUANTUM XP34301", 15) == 0) &&
11024 (strncmp(inq->product_rev_level, "1071", 4) == 0)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011025 return 0;
11026 }
11027 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011028}
11029
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011030static void
11031AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011032{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011033 ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
11034 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011035
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011036 orig_init_sdtr = asc_dvc->init_sdtr;
11037 orig_use_tagged_qng = asc_dvc->use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011038
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011039 asc_dvc->init_sdtr &= ~tid_bit;
11040 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
11041 asc_dvc->use_tagged_qng &= ~tid_bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011042
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011043 if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
11044 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
11045 asc_dvc->init_sdtr |= tid_bit;
11046 }
11047 if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
11048 ASC_INQ_CMD_QUEUE(inq)) {
11049 if (AscTagQueuingSafe(inq)) {
11050 asc_dvc->use_tagged_qng |= tid_bit;
11051 asc_dvc->cfg->can_tagged_qng |= tid_bit;
11052 }
11053 }
11054 }
11055 if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
11056 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
11057 asc_dvc->cfg->disc_enable);
11058 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
11059 asc_dvc->use_tagged_qng);
11060 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
11061 asc_dvc->cfg->can_tagged_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011062
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011063 asc_dvc->max_dvc_qng[tid_no] =
11064 asc_dvc->cfg->max_tag_qng[tid_no];
11065 AscWriteLramByte(asc_dvc->iop_base,
11066 (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no),
11067 asc_dvc->max_dvc_qng[tid_no]);
11068 }
11069 if (orig_init_sdtr != asc_dvc->init_sdtr) {
11070 AscAsyncFix(asc_dvc, tid_no, inq);
11071 }
11072 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011073}
11074
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011075static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011076{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011077 uchar byte_data;
11078 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011079
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011080 if (isodd_word(addr)) {
11081 AscSetChipLramAddr(iop_base, addr - 1);
11082 word_data = AscGetChipLramData(iop_base);
11083 byte_data = (uchar)((word_data >> 8) & 0xFF);
11084 } else {
11085 AscSetChipLramAddr(iop_base, addr);
11086 word_data = AscGetChipLramData(iop_base);
11087 byte_data = (uchar)(word_data & 0xFF);
11088 }
11089 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011090}
Linus Torvalds1da177e2005-04-16 15:20:36 -070011091
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011092static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
11093{
11094 ushort word_data;
11095
11096 AscSetChipLramAddr(iop_base, addr);
11097 word_data = AscGetChipLramData(iop_base);
11098 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011099}
11100
11101#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011102static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011103{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011104 ushort val_low, val_high;
11105 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011106
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011107 AscSetChipLramAddr(iop_base, addr);
11108 val_low = AscGetChipLramData(iop_base);
11109 val_high = AscGetChipLramData(iop_base);
11110 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
11111 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011112}
11113#endif /* CC_VERY_LONG_SG_LIST */
11114
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011115static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011116{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011117 AscSetChipLramAddr(iop_base, addr);
11118 AscSetChipLramData(iop_base, word_val);
11119 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011120}
11121
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011122static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011123{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011124 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011125
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011126 if (isodd_word(addr)) {
11127 addr--;
11128 word_data = AscReadLramWord(iop_base, addr);
11129 word_data &= 0x00FF;
11130 word_data |= (((ushort)byte_val << 8) & 0xFF00);
11131 } else {
11132 word_data = AscReadLramWord(iop_base, addr);
11133 word_data &= 0xFF00;
11134 word_data |= ((ushort)byte_val & 0x00FF);
11135 }
11136 AscWriteLramWord(iop_base, addr, word_data);
11137 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011138}
11139
11140/*
11141 * Copy 2 bytes to LRAM.
11142 *
11143 * The source data is assumed to be in little-endian order in memory
11144 * and is maintained in little-endian order when written to LRAM.
11145 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011146static void
11147AscMemWordCopyPtrToLram(PortAddr iop_base,
11148 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011149{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011150 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011151
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011152 AscSetChipLramAddr(iop_base, s_addr);
11153 for (i = 0; i < 2 * words; i += 2) {
11154 /*
11155 * On a little-endian system the second argument below
11156 * produces a little-endian ushort which is written to
11157 * LRAM in little-endian order. On a big-endian system
11158 * the second argument produces a big-endian ushort which
11159 * is "transparently" byte-swapped by outpw() and written
11160 * in little-endian order to LRAM.
11161 */
11162 outpw(iop_base + IOP_RAM_DATA,
11163 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
11164 }
11165 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011166}
11167
11168/*
11169 * Copy 4 bytes to LRAM.
11170 *
11171 * The source data is assumed to be in little-endian order in memory
11172 * and is maintained in little-endian order when writen to LRAM.
11173 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011174static void
11175AscMemDWordCopyPtrToLram(PortAddr iop_base,
11176 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011177{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011178 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011179
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011180 AscSetChipLramAddr(iop_base, s_addr);
11181 for (i = 0; i < 4 * dwords; i += 4) {
11182 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11183 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11184 }
11185 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011186}
11187
11188/*
11189 * Copy 2 bytes from LRAM.
11190 *
11191 * The source data is assumed to be in little-endian order in LRAM
11192 * and is maintained in little-endian order when written to memory.
11193 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011194static void
11195AscMemWordCopyPtrFromLram(PortAddr iop_base,
11196 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011197{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011198 int i;
11199 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011200
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011201 AscSetChipLramAddr(iop_base, s_addr);
11202 for (i = 0; i < 2 * words; i += 2) {
11203 word = inpw(iop_base + IOP_RAM_DATA);
11204 d_buffer[i] = word & 0xff;
11205 d_buffer[i + 1] = (word >> 8) & 0xff;
11206 }
11207 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011208}
11209
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011210static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011211{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011212 ASC_DCNT sum;
11213 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011214
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011215 sum = 0L;
11216 for (i = 0; i < words; i++, s_addr += 2) {
11217 sum += AscReadLramWord(iop_base, s_addr);
11218 }
11219 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011220}
11221
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011222static void
11223AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011224{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011225 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011226
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011227 AscSetChipLramAddr(iop_base, s_addr);
11228 for (i = 0; i < words; i++) {
11229 AscSetChipLramData(iop_base, set_wval);
11230 }
11231 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011232}
11233
Linus Torvalds1da177e2005-04-16 15:20:36 -070011234/*
11235 * --- Adv Library Functions
11236 */
11237
11238/* a_mcode.h */
11239
11240/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011241static unsigned char _adv_asc3550_buf[] = {
11242 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11243 0x01, 0x00, 0x48, 0xe4,
11244 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11245 0x28, 0x0e, 0x9e, 0xe7,
11246 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11247 0x55, 0xf0, 0x01, 0xf6,
11248 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11249 0x00, 0xec, 0x85, 0xf0,
11250 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11251 0x86, 0xf0, 0xb4, 0x00,
11252 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11253 0xaa, 0x18, 0x02, 0x80,
11254 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11255 0x00, 0x57, 0x01, 0xea,
11256 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11257 0x03, 0xe6, 0xb6, 0x00,
11258 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11259 0x02, 0x4a, 0xb9, 0x54,
11260 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11261 0x3e, 0x00, 0x80, 0x00,
11262 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11263 0x74, 0x01, 0x76, 0x01,
11264 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11265 0x4c, 0x1c, 0xbb, 0x55,
11266 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11267 0x03, 0xf7, 0x06, 0xf7,
11268 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11269 0x30, 0x13, 0x64, 0x15,
11270 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11271 0x04, 0xea, 0x5d, 0xf0,
11272 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11273 0xcc, 0x00, 0x20, 0x01,
11274 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11275 0x40, 0x13, 0x30, 0x1c,
11276 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11277 0x59, 0xf0, 0xa7, 0xf0,
11278 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11279 0xa4, 0x00, 0xb5, 0x00,
11280 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11281 0x14, 0x0e, 0x02, 0x10,
11282 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11283 0x10, 0x15, 0x14, 0x15,
11284 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11285 0x91, 0x44, 0x0a, 0x45,
11286 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11287 0x83, 0x59, 0x05, 0xe6,
11288 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11289 0x02, 0xfa, 0x03, 0xfa,
11290 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11291 0x9e, 0x00, 0xa8, 0x00,
11292 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11293 0x7a, 0x01, 0xc0, 0x01,
11294 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11295 0x69, 0x08, 0xba, 0x08,
11296 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11297 0xf1, 0x10, 0x06, 0x12,
11298 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11299 0x8a, 0x15, 0xc6, 0x17,
11300 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11301 0x0e, 0x47, 0x48, 0x47,
11302 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11303 0x14, 0x56, 0x77, 0x57,
11304 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11305 0xf0, 0x29, 0x02, 0xfe,
11306 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11307 0xfe, 0x80, 0x01, 0xff,
11308 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11309 0x00, 0xfe, 0x57, 0x24,
11310 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11311 0x00, 0x00, 0xff, 0x08,
11312 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11313 0xff, 0xff, 0xff, 0x0f,
11314 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11315 0xfe, 0x04, 0xf7, 0xcf,
11316 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11317 0x0b, 0x3c, 0x2a, 0xfe,
11318 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11319 0xfe, 0xf0, 0x01, 0xfe,
11320 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11321 0x02, 0xfe, 0xd4, 0x0c,
11322 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11323 0x1c, 0x05, 0xfe, 0xa6,
11324 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11325 0xf0, 0xfe, 0x86, 0x02,
11326 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11327 0xfe, 0x46, 0xf0, 0xfe,
11328 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11329 0x44, 0x02, 0xfe, 0x44,
11330 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11331 0xa0, 0x17, 0x06, 0x18,
11332 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11333 0x1e, 0x1c, 0xfe, 0xe9,
11334 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11335 0x0a, 0x6b, 0x01, 0x9e,
11336 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11337 0x01, 0x82, 0xfe, 0xbd,
11338 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11339 0x58, 0x1c, 0x17, 0x06,
11340 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11341 0xfe, 0x94, 0x02, 0xfe,
11342 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11343 0x01, 0xfe, 0x54, 0x0f,
11344 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11345 0x69, 0x10, 0x17, 0x06,
11346 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11347 0xf6, 0xc7, 0x01, 0xfe,
11348 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11349 0x02, 0x29, 0x0a, 0x40,
11350 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11351 0x58, 0x0a, 0x99, 0x01,
11352 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11353 0x2a, 0x46, 0xfe, 0x02,
11354 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11355 0x01, 0xfe, 0x07, 0x4b,
11356 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11357 0xfe, 0x56, 0x03, 0xfe,
11358 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11359 0xfe, 0x9f, 0xf0, 0xfe,
11360 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11361 0x1c, 0xeb, 0x09, 0x04,
11362 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11363 0x01, 0x0e, 0xac, 0x75,
11364 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11365 0xfe, 0x82, 0xf0, 0xfe,
11366 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11367 0x32, 0x1f, 0xfe, 0xb4,
11368 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11369 0x0a, 0xf0, 0xfe, 0x7a,
11370 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11371 0x01, 0x33, 0x8f, 0xfe,
11372 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11373 0xf7, 0xfe, 0x48, 0x1c,
11374 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11375 0x0a, 0xca, 0x01, 0x0e,
11376 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11377 0x2c, 0x01, 0x33, 0x8f,
11378 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11379 0xfe, 0x3c, 0x04, 0x1f,
11380 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11381 0x12, 0x2b, 0xff, 0x02,
11382 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11383 0x22, 0x30, 0x2e, 0xd5,
11384 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11385 0xfe, 0x4c, 0x54, 0x64,
11386 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11387 0xfe, 0x2a, 0x13, 0x2f,
11388 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11389 0xd3, 0xfa, 0xef, 0x86,
11390 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11391 0x1d, 0xfe, 0x1c, 0x12,
11392 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11393 0x70, 0x0c, 0x02, 0x22,
11394 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11395 0x01, 0x33, 0x02, 0x29,
11396 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11397 0x80, 0xfe, 0x31, 0xe4,
11398 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11399 0xfe, 0x70, 0x12, 0x49,
11400 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11401 0x80, 0x05, 0xfe, 0x31,
11402 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11403 0x28, 0xfe, 0x42, 0x12,
11404 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11405 0x11, 0xfe, 0xe3, 0x00,
11406 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11407 0x64, 0x05, 0x83, 0x24,
11408 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11409 0x09, 0x48, 0x01, 0x08,
11410 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11411 0x86, 0x24, 0x06, 0x12,
11412 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11413 0x01, 0xa7, 0x14, 0x92,
11414 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11415 0x02, 0x22, 0x05, 0xfe,
11416 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11417 0x47, 0x01, 0xa7, 0x26,
11418 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11419 0x01, 0xfe, 0xaa, 0x14,
11420 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11421 0x05, 0x50, 0xb4, 0x0c,
11422 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11423 0x13, 0x01, 0xfe, 0x14,
11424 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11425 0xff, 0x02, 0x00, 0x57,
11426 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11427 0x72, 0x06, 0x49, 0x04,
11428 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11429 0x06, 0x11, 0x9a, 0x01,
11430 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11431 0x01, 0xa7, 0xec, 0x72,
11432 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11433 0xfe, 0x0a, 0xf0, 0xfe,
11434 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11435 0x8d, 0x81, 0x02, 0x22,
11436 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11437 0x01, 0x08, 0x15, 0x00,
11438 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11439 0x00, 0x02, 0xfe, 0x32,
11440 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11441 0xfe, 0x1b, 0x00, 0x01,
11442 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11443 0x08, 0x15, 0x06, 0x01,
11444 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11445 0x9a, 0x81, 0x4b, 0x1d,
11446 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11447 0x45, 0xfe, 0x32, 0x12,
11448 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11449 0xfe, 0x32, 0x07, 0x8d,
11450 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11451 0x06, 0x15, 0x19, 0x02,
11452 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11453 0x90, 0x77, 0xfe, 0xca,
11454 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11455 0x10, 0xfe, 0x0e, 0x12,
11456 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11457 0x83, 0xe7, 0xc4, 0xa1,
11458 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11459 0x40, 0x12, 0x58, 0x01,
11460 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11461 0x51, 0x83, 0xfb, 0xfe,
11462 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11463 0xfe, 0x40, 0x50, 0xfe,
11464 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11465 0xfe, 0x2a, 0x12, 0xfe,
11466 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11467 0x85, 0x01, 0xa8, 0xfe,
11468 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11469 0x18, 0x57, 0xfb, 0xfe,
11470 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11471 0x0c, 0x39, 0x18, 0x3a,
11472 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11473 0x11, 0x65, 0xfe, 0x48,
11474 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11475 0xdd, 0xb8, 0xfe, 0x80,
11476 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11477 0xfe, 0x7a, 0x08, 0x8d,
11478 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11479 0x10, 0x61, 0x04, 0x06,
11480 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11481 0x12, 0xfe, 0x2e, 0x1c,
11482 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11483 0x52, 0x12, 0xfe, 0x2c,
11484 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11485 0x08, 0xfe, 0x8a, 0x10,
11486 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11487 0x24, 0x0a, 0xab, 0xfe,
11488 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11489 0x1c, 0x12, 0xb5, 0xfe,
11490 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11491 0x1c, 0x06, 0x16, 0x9d,
11492 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11493 0x14, 0x92, 0x01, 0x33,
11494 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11495 0xfe, 0x74, 0x18, 0x1c,
11496 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11497 0x01, 0xe6, 0x1e, 0x27,
11498 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11499 0x09, 0x04, 0x6a, 0xfe,
11500 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11501 0xfe, 0x83, 0x80, 0xfe,
11502 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11503 0x27, 0xfe, 0x40, 0x59,
11504 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11505 0x7c, 0xbe, 0x54, 0xbf,
11506 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11507 0x79, 0x56, 0x68, 0x57,
11508 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11509 0xa2, 0x23, 0x0c, 0x7b,
11510 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11511 0x16, 0xd7, 0x79, 0x39,
11512 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11513 0xfe, 0x10, 0x58, 0xfe,
11514 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
11515 0x19, 0x16, 0xd7, 0x09,
11516 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
11517 0xfe, 0x10, 0x90, 0xfe,
11518 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
11519 0x11, 0x9b, 0x09, 0x04,
11520 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
11521 0xfe, 0x0c, 0x58, 0xfe,
11522 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
11523 0x0b, 0xfe, 0x1a, 0x12,
11524 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
11525 0x14, 0x7a, 0x01, 0x33,
11526 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
11527 0xfe, 0xed, 0x19, 0xbf,
11528 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
11529 0x34, 0xfe, 0x74, 0x10,
11530 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
11531 0x84, 0x05, 0xcb, 0x1c,
11532 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
11533 0xf0, 0xfe, 0xc4, 0x0a,
11534 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
11535 0xce, 0xf0, 0xfe, 0xca,
11536 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
11537 0x22, 0x00, 0x02, 0x5a,
11538 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
11539 0xfe, 0xd0, 0xf0, 0xfe,
11540 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
11541 0x4c, 0xfe, 0x10, 0x10,
11542 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
11543 0x2a, 0x13, 0xfe, 0x4e,
11544 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
11545 0x16, 0x32, 0x2a, 0x73,
11546 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
11547 0x32, 0x8c, 0xfe, 0x48,
11548 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
11549 0xdb, 0x10, 0x11, 0xfe,
11550 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
11551 0x22, 0x30, 0x2e, 0xd8,
11552 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
11553 0x45, 0x0f, 0xfe, 0x42,
11554 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
11555 0x09, 0x04, 0x0b, 0xfe,
11556 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
11557 0x00, 0x21, 0xfe, 0xa6,
11558 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
11559 0xfe, 0xe2, 0x10, 0x01,
11560 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
11561 0x01, 0x6f, 0x02, 0x29,
11562 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
11563 0x01, 0x86, 0x3e, 0x0b,
11564 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
11565 0x3e, 0x0b, 0x0f, 0xfe,
11566 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
11567 0xe8, 0x59, 0x11, 0x2d,
11568 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
11569 0x04, 0x0b, 0x84, 0x3e,
11570 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
11571 0x09, 0x04, 0x1b, 0xfe,
11572 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
11573 0x1c, 0x1c, 0xfe, 0x9d,
11574 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
11575 0xfe, 0x15, 0x00, 0xfe,
11576 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
11577 0x0f, 0xfe, 0x47, 0x00,
11578 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
11579 0xab, 0x70, 0x05, 0x6b,
11580 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
11581 0x1c, 0x42, 0x59, 0x01,
11582 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
11583 0x00, 0x37, 0x97, 0x01,
11584 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
11585 0x1d, 0xfe, 0xce, 0x45,
11586 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
11587 0x57, 0x05, 0x51, 0xfe,
11588 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
11589 0x46, 0x09, 0x04, 0x1d,
11590 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
11591 0x99, 0x01, 0x0e, 0xfe,
11592 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
11593 0xfe, 0xee, 0x14, 0xee,
11594 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
11595 0x13, 0x02, 0x29, 0x1e,
11596 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
11597 0xce, 0x1e, 0x2d, 0x47,
11598 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
11599 0x12, 0x4d, 0x01, 0xfe,
11600 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
11601 0xf0, 0x0d, 0xfe, 0x02,
11602 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
11603 0xf6, 0xfe, 0x34, 0x01,
11604 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
11605 0xaf, 0xfe, 0x02, 0xea,
11606 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
11607 0x05, 0xfe, 0x38, 0x01,
11608 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
11609 0x0c, 0xfe, 0x62, 0x01,
11610 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
11611 0x03, 0x23, 0x03, 0x1e,
11612 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
11613 0x71, 0x13, 0xfe, 0x24,
11614 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
11615 0xdc, 0xfe, 0x73, 0x57,
11616 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
11617 0x80, 0x5d, 0x03, 0xfe,
11618 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
11619 0x75, 0x03, 0x09, 0x04,
11620 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
11621 0xfe, 0x1e, 0x80, 0xe1,
11622 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
11623 0x90, 0xa3, 0xfe, 0x3c,
11624 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
11625 0x16, 0x2f, 0x07, 0x2d,
11626 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
11627 0xe8, 0x11, 0xfe, 0xe9,
11628 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
11629 0x1e, 0x1c, 0xfe, 0x14,
11630 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
11631 0x09, 0x04, 0x4f, 0xfe,
11632 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
11633 0x40, 0x12, 0x20, 0x63,
11634 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
11635 0x1c, 0x05, 0xfe, 0xac,
11636 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
11637 0xfe, 0xb0, 0x00, 0xfe,
11638 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
11639 0x24, 0x69, 0x12, 0xc9,
11640 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
11641 0x90, 0x4d, 0xfe, 0x91,
11642 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
11643 0xfe, 0x90, 0x4d, 0xfe,
11644 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
11645 0x46, 0x1e, 0x20, 0xed,
11646 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
11647 0x70, 0xfe, 0x14, 0x1c,
11648 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
11649 0xfe, 0x07, 0xe6, 0x1d,
11650 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
11651 0xfa, 0xef, 0xfe, 0x42,
11652 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
11653 0xfe, 0x36, 0x12, 0xf0,
11654 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
11655 0x3d, 0x75, 0x07, 0x10,
11656 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
11657 0x10, 0x07, 0x7e, 0x45,
11658 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
11659 0xfe, 0x01, 0xec, 0x97,
11660 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
11661 0x27, 0x01, 0xda, 0xfe,
11662 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
11663 0xfe, 0x48, 0x12, 0x07,
11664 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
11665 0xfe, 0x3e, 0x11, 0x07,
11666 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
11667 0x11, 0x07, 0x19, 0xfe,
11668 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
11669 0x01, 0x08, 0x8c, 0x43,
11670 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
11671 0x7e, 0x02, 0x29, 0x2b,
11672 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
11673 0xfc, 0x10, 0x09, 0x04,
11674 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
11675 0xc6, 0x10, 0x1e, 0x58,
11676 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
11677 0x54, 0x18, 0x55, 0x23,
11678 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
11679 0xa5, 0xc0, 0x38, 0xc1,
11680 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
11681 0x05, 0xfa, 0x4e, 0xfe,
11682 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
11683 0x0c, 0x56, 0x18, 0x57,
11684 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
11685 0x00, 0x56, 0xfe, 0xa1,
11686 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
11687 0x58, 0xfe, 0x1f, 0x40,
11688 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
11689 0x31, 0x57, 0xfe, 0x44,
11690 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
11691 0x8a, 0x50, 0x05, 0x39,
11692 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
11693 0x12, 0xcd, 0x02, 0x5b,
11694 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
11695 0x2f, 0x07, 0x9b, 0x21,
11696 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
11697 0x39, 0x68, 0x3a, 0xfe,
11698 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
11699 0x51, 0xfe, 0x8e, 0x51,
11700 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
11701 0x01, 0x08, 0x25, 0x32,
11702 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
11703 0x3b, 0x02, 0x44, 0x01,
11704 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
11705 0x01, 0x08, 0x1f, 0xa2,
11706 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
11707 0x00, 0x28, 0x84, 0x49,
11708 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
11709 0x78, 0x3d, 0xfe, 0xda,
11710 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
11711 0x05, 0xc6, 0x28, 0x84,
11712 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
11713 0x14, 0xfe, 0x03, 0x17,
11714 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
11715 0xfe, 0xaa, 0x14, 0x02,
11716 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
11717 0x21, 0x44, 0x01, 0xfe,
11718 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
11719 0xfe, 0x4a, 0xf4, 0x0b,
11720 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
11721 0x85, 0x02, 0x5b, 0x05,
11722 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
11723 0xd8, 0x14, 0x02, 0x5c,
11724 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
11725 0x01, 0x08, 0x23, 0x72,
11726 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
11727 0x12, 0x5e, 0x2b, 0x01,
11728 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
11729 0x1c, 0xfe, 0xff, 0x7f,
11730 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
11731 0x57, 0x48, 0x8b, 0x1c,
11732 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
11733 0x00, 0x57, 0x48, 0x8b,
11734 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
11735 0x03, 0x0a, 0x50, 0x01,
11736 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
11737 0x54, 0xfe, 0x00, 0xf4,
11738 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
11739 0x03, 0x7c, 0x63, 0x27,
11740 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
11741 0xfe, 0x82, 0x4a, 0xfe,
11742 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
11743 0x42, 0x48, 0x5f, 0x60,
11744 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
11745 0x1f, 0xfe, 0xa2, 0x14,
11746 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
11747 0xcc, 0x12, 0x49, 0x04,
11748 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
11749 0xe8, 0x13, 0x3b, 0x13,
11750 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
11751 0xa1, 0xff, 0x02, 0x83,
11752 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
11753 0x13, 0x06, 0xfe, 0x56,
11754 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
11755 0x64, 0x00, 0x17, 0x93,
11756 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
11757 0xc8, 0x00, 0x8e, 0xe4,
11758 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
11759 0x01, 0xba, 0xfe, 0x4e,
11760 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
11761 0xfe, 0x60, 0x14, 0xfe,
11762 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
11763 0xfe, 0x22, 0x13, 0x1c,
11764 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
11765 0xfe, 0x9c, 0x14, 0xb7,
11766 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
11767 0xfe, 0x9c, 0x14, 0xb7,
11768 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
11769 0xfe, 0xb4, 0x56, 0xfe,
11770 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
11771 0xe5, 0x15, 0x0b, 0x01,
11772 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
11773 0x49, 0x01, 0x08, 0x03,
11774 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
11775 0x15, 0x06, 0x01, 0x08,
11776 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
11777 0x4a, 0x01, 0x08, 0x03,
11778 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
11779 0xfe, 0x49, 0xf4, 0x00,
11780 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
11781 0x08, 0x2f, 0x07, 0xfe,
11782 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
11783 0x01, 0x43, 0x1e, 0xcd,
11784 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11785 0xed, 0x88, 0x07, 0x10,
11786 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
11787 0x80, 0x01, 0x0e, 0x88,
11788 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
11789 0x88, 0x03, 0x0a, 0x42,
11790 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11791 0xfe, 0x80, 0x80, 0xf2,
11792 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
11793 0x01, 0x82, 0x03, 0x17,
11794 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
11795 0xfe, 0x24, 0x1c, 0xfe,
11796 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
11797 0x91, 0x1d, 0x66, 0xfe,
11798 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
11799 0xda, 0x10, 0x17, 0x10,
11800 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
11801 0x05, 0xfe, 0x66, 0x01,
11802 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
11803 0xfe, 0x3c, 0x50, 0x66,
11804 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
11805 0x40, 0x16, 0xfe, 0xb6,
11806 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
11807 0x10, 0x71, 0xfe, 0x83,
11808 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
11809 0xfe, 0x62, 0x16, 0xfe,
11810 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
11811 0xfe, 0x98, 0xe7, 0x00,
11812 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
11813 0xfe, 0x30, 0xbc, 0xfe,
11814 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
11815 0xc5, 0x90, 0xfe, 0x9a,
11816 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
11817 0x42, 0x10, 0xfe, 0x02,
11818 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
11819 0xfe, 0x1d, 0xf7, 0x4f,
11820 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
11821 0x47, 0xfe, 0x83, 0x58,
11822 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
11823 0xfe, 0xdd, 0x00, 0x63,
11824 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
11825 0x06, 0x37, 0x95, 0xa9,
11826 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
11827 0x18, 0x1c, 0x1a, 0x5d,
11828 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
11829 0xe1, 0x10, 0x78, 0x2c,
11830 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
11831 0x13, 0x3c, 0x8a, 0x0a,
11832 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
11833 0xe3, 0xfe, 0x00, 0xcc,
11834 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
11835 0x0e, 0xf2, 0x01, 0x6f,
11836 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
11837 0xf6, 0xfe, 0xd6, 0xf0,
11838 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
11839 0x15, 0x00, 0x59, 0x76,
11840 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
11841 0x11, 0x2d, 0x01, 0x6f,
11842 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
11843 0xc8, 0xfe, 0x48, 0x55,
11844 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
11845 0x99, 0x01, 0x0e, 0xf0,
11846 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
11847 0x75, 0x03, 0x0a, 0x42,
11848 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
11849 0x0e, 0x73, 0x75, 0x03,
11850 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
11851 0xfe, 0x3a, 0x45, 0x5b,
11852 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
11853 0xfe, 0x02, 0xe6, 0x1b,
11854 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
11855 0xfe, 0x94, 0x00, 0xfe,
11856 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
11857 0xe6, 0x2c, 0xfe, 0x4e,
11858 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
11859 0x03, 0x07, 0x7a, 0xfe,
11860 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
11861 0x07, 0x1b, 0xfe, 0x5a,
11862 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
11863 0x24, 0x2c, 0xdc, 0x07,
11864 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
11865 0x9f, 0xad, 0x03, 0x14,
11866 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
11867 0x03, 0x25, 0xfe, 0xca,
11868 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
11869 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011870};
11871
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011872static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
11873static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011874
11875/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011876static unsigned char _adv_asc38C0800_buf[] = {
11877 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
11878 0x01, 0x00, 0x48, 0xe4,
11879 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
11880 0x1c, 0x0f, 0x00, 0xf6,
11881 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
11882 0x09, 0xe7, 0x55, 0xf0,
11883 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
11884 0x18, 0xf4, 0x08, 0x00,
11885 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
11886 0x86, 0xf0, 0xb1, 0xf0,
11887 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
11888 0x3c, 0x00, 0xbb, 0x00,
11889 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
11890 0xba, 0x13, 0x18, 0x40,
11891 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
11892 0x6e, 0x01, 0x74, 0x01,
11893 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
11894 0xc0, 0x00, 0x01, 0x01,
11895 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
11896 0x08, 0x12, 0x02, 0x4a,
11897 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
11898 0x5d, 0xf0, 0x02, 0xfa,
11899 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
11900 0x68, 0x01, 0x6a, 0x01,
11901 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
11902 0x06, 0x13, 0x4c, 0x1c,
11903 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
11904 0x0f, 0x00, 0x47, 0x00,
11905 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
11906 0x4e, 0x1c, 0x10, 0x44,
11907 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
11908 0x05, 0x00, 0x34, 0x00,
11909 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
11910 0x42, 0x0c, 0x12, 0x0f,
11911 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
11912 0x00, 0x4e, 0x42, 0x54,
11913 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11914 0x59, 0xf0, 0xb8, 0xf0,
11915 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
11916 0x19, 0x00, 0x33, 0x00,
11917 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
11918 0xe7, 0x00, 0xe2, 0x03,
11919 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
11920 0x12, 0x13, 0x24, 0x14,
11921 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
11922 0x36, 0x1c, 0x08, 0x44,
11923 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
11924 0x3a, 0x55, 0x83, 0x55,
11925 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
11926 0x0c, 0xf0, 0x04, 0xf8,
11927 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
11928 0xa8, 0x00, 0xaa, 0x00,
11929 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
11930 0xc4, 0x01, 0xc6, 0x01,
11931 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
11932 0x68, 0x08, 0x69, 0x08,
11933 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
11934 0xed, 0x10, 0xf1, 0x10,
11935 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
11936 0x1e, 0x13, 0x46, 0x14,
11937 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
11938 0xca, 0x18, 0xe6, 0x19,
11939 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
11940 0xf0, 0x2b, 0x02, 0xfe,
11941 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
11942 0xfe, 0x84, 0x01, 0xff,
11943 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11944 0x00, 0xfe, 0x57, 0x24,
11945 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
11946 0x00, 0x00, 0xff, 0x08,
11947 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11948 0xff, 0xff, 0xff, 0x11,
11949 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11950 0xfe, 0x04, 0xf7, 0xd6,
11951 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
11952 0x0a, 0x42, 0x2c, 0xfe,
11953 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
11954 0xfe, 0xf4, 0x01, 0xfe,
11955 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
11956 0x02, 0xfe, 0xc8, 0x0d,
11957 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11958 0x1c, 0x03, 0xfe, 0xa6,
11959 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
11960 0xf0, 0xfe, 0x8a, 0x02,
11961 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
11962 0xfe, 0x46, 0xf0, 0xfe,
11963 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11964 0x48, 0x02, 0xfe, 0x44,
11965 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
11966 0xaa, 0x18, 0x06, 0x14,
11967 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
11968 0x1e, 0x1c, 0xfe, 0xe9,
11969 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
11970 0x09, 0x70, 0x01, 0xa8,
11971 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
11972 0x01, 0x87, 0xfe, 0xbd,
11973 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11974 0x58, 0x1c, 0x18, 0x06,
11975 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
11976 0xfe, 0x98, 0x02, 0xfe,
11977 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
11978 0x01, 0xfe, 0x48, 0x10,
11979 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
11980 0x69, 0x10, 0x18, 0x06,
11981 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
11982 0xf6, 0xce, 0x01, 0xfe,
11983 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
11984 0x82, 0x16, 0x02, 0x2b,
11985 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
11986 0xfe, 0x41, 0x58, 0x09,
11987 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
11988 0x82, 0x16, 0x02, 0x2b,
11989 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
11990 0xfe, 0x77, 0x57, 0xfe,
11991 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
11992 0xfe, 0x40, 0x1c, 0x1c,
11993 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
11994 0x03, 0xfe, 0x11, 0xf0,
11995 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
11996 0xfe, 0x11, 0x00, 0x02,
11997 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
11998 0x21, 0x22, 0xa3, 0xb7,
11999 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
12000 0x12, 0xd1, 0x1c, 0xd9,
12001 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
12002 0xfe, 0xe4, 0x00, 0x27,
12003 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
12004 0x06, 0xf0, 0xfe, 0xc8,
12005 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
12006 0x70, 0x28, 0x17, 0xfe,
12007 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
12008 0xf9, 0x2c, 0x99, 0x19,
12009 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
12010 0x74, 0x01, 0xaf, 0x8c,
12011 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
12012 0x8d, 0x51, 0x64, 0x79,
12013 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
12014 0xfe, 0x6a, 0x02, 0x02,
12015 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
12016 0xfe, 0x3c, 0x04, 0x3b,
12017 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
12018 0x00, 0x10, 0x01, 0x0b,
12019 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
12020 0xfe, 0x4c, 0x44, 0xfe,
12021 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
12022 0xda, 0x4f, 0x79, 0x2a,
12023 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
12024 0xfe, 0x2a, 0x13, 0x32,
12025 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
12026 0x54, 0x6b, 0xda, 0xfe,
12027 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
12028 0x08, 0x13, 0x32, 0x07,
12029 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
12030 0x08, 0x05, 0x06, 0x4d,
12031 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
12032 0x2d, 0x12, 0xfe, 0xe6,
12033 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
12034 0x02, 0x2b, 0xfe, 0x42,
12035 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12036 0xfe, 0x87, 0x80, 0xfe,
12037 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
12038 0x07, 0x19, 0xfe, 0x7c,
12039 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
12040 0x17, 0xfe, 0x90, 0x05,
12041 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
12042 0xa0, 0x00, 0x28, 0xfe,
12043 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
12044 0x34, 0xfe, 0x89, 0x48,
12045 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
12046 0x12, 0xfe, 0xe3, 0x00,
12047 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
12048 0x70, 0x05, 0x88, 0x25,
12049 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
12050 0x09, 0x48, 0xff, 0x02,
12051 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
12052 0x08, 0x53, 0x05, 0xcb,
12053 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
12054 0x05, 0x1b, 0xfe, 0x22,
12055 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
12056 0x0d, 0x00, 0x01, 0x36,
12057 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
12058 0x03, 0x5c, 0x28, 0xfe,
12059 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
12060 0x05, 0x1f, 0xfe, 0x02,
12061 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
12062 0x01, 0x4b, 0x12, 0xfe,
12063 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
12064 0x12, 0x03, 0x45, 0x28,
12065 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
12066 0x43, 0x48, 0xc4, 0xcc,
12067 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
12068 0x6e, 0x41, 0x01, 0xb2,
12069 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
12070 0xfe, 0xcc, 0x15, 0x1d,
12071 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
12072 0x45, 0xc1, 0x0c, 0x45,
12073 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
12074 0xe2, 0x00, 0x27, 0xdb,
12075 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
12076 0xfe, 0x06, 0xf0, 0xfe,
12077 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
12078 0x16, 0x19, 0x01, 0x0b,
12079 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
12080 0xfe, 0x99, 0xa4, 0x01,
12081 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
12082 0x12, 0x08, 0x05, 0x1a,
12083 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
12084 0x0b, 0x16, 0x00, 0x01,
12085 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
12086 0xe2, 0x6c, 0x58, 0xbe,
12087 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
12088 0xfe, 0x09, 0x6f, 0xba,
12089 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
12090 0xfe, 0x54, 0x07, 0x1c,
12091 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
12092 0x07, 0x02, 0x24, 0x01,
12093 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
12094 0x2c, 0x90, 0xfe, 0xae,
12095 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
12096 0x37, 0x22, 0x20, 0x07,
12097 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
12098 0xfe, 0x06, 0x10, 0xfe,
12099 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
12100 0x37, 0x01, 0xb3, 0xb8,
12101 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
12102 0x50, 0xfe, 0x44, 0x51,
12103 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
12104 0x14, 0x5f, 0xfe, 0x0c,
12105 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
12106 0x14, 0x3e, 0xfe, 0x4a,
12107 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
12108 0x90, 0x0c, 0x60, 0x14,
12109 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
12110 0xfe, 0x44, 0x90, 0xfe,
12111 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
12112 0x0c, 0x5e, 0x14, 0x5f,
12113 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
12114 0x14, 0x3c, 0x21, 0x0c,
12115 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
12116 0x27, 0xdd, 0xfe, 0x9e,
12117 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
12118 0x9a, 0x08, 0xc6, 0xfe,
12119 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
12120 0x95, 0x86, 0x02, 0x24,
12121 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
12122 0x06, 0xfe, 0x10, 0x12,
12123 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
12124 0x1c, 0x02, 0xfe, 0x18,
12125 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
12126 0x2c, 0x1c, 0xfe, 0xaa,
12127 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
12128 0xde, 0x09, 0xfe, 0xb7,
12129 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
12130 0xfe, 0xf1, 0x18, 0xfe,
12131 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
12132 0x14, 0x59, 0xfe, 0x95,
12133 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
12134 0xfe, 0xf0, 0x08, 0xb5,
12135 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
12136 0x0b, 0xb6, 0xfe, 0xbf,
12137 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
12138 0x12, 0xc2, 0xfe, 0xd2,
12139 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
12140 0x06, 0x17, 0x85, 0xc5,
12141 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
12142 0x9d, 0x01, 0x36, 0x10,
12143 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
12144 0x98, 0x80, 0xfe, 0x19,
12145 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
12146 0xfe, 0x44, 0x54, 0xbe,
12147 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
12148 0x02, 0x4a, 0x08, 0x05,
12149 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
12150 0x9c, 0x3c, 0xfe, 0x6c,
12151 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
12152 0x3b, 0x40, 0x03, 0x49,
12153 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
12154 0x8f, 0xfe, 0xe3, 0x54,
12155 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
12156 0xda, 0x09, 0xfe, 0x8b,
12157 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
12158 0x0a, 0x3a, 0x49, 0x3b,
12159 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
12160 0xad, 0xfe, 0x01, 0x59,
12161 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
12162 0x49, 0x8f, 0xfe, 0xe3,
12163 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
12164 0x4a, 0x3a, 0x49, 0x3b,
12165 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
12166 0x02, 0x4a, 0x08, 0x05,
12167 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
12168 0xb7, 0xfe, 0x03, 0xa1,
12169 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12170 0xfe, 0x86, 0x91, 0x6a,
12171 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12172 0x61, 0x0c, 0x7f, 0x14,
12173 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12174 0x9b, 0x2e, 0x9c, 0x3c,
12175 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12176 0xfa, 0x3c, 0x01, 0xef,
12177 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12178 0xe4, 0x08, 0x05, 0x1f,
12179 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12180 0x03, 0x5e, 0x29, 0x5f,
12181 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12182 0xf4, 0x09, 0x08, 0x05,
12183 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12184 0x81, 0x50, 0xfe, 0x10,
12185 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12186 0x08, 0x09, 0x12, 0xa6,
12187 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12188 0x08, 0x09, 0xfe, 0x0c,
12189 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12190 0x08, 0x05, 0x0a, 0xfe,
12191 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12192 0xf0, 0xe2, 0x15, 0x7e,
12193 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12194 0x57, 0x3d, 0xfe, 0xed,
12195 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12196 0x00, 0xff, 0x35, 0xfe,
12197 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12198 0x1e, 0x19, 0x8a, 0x03,
12199 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12200 0xfe, 0xd1, 0xf0, 0xfe,
12201 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12202 0x10, 0xfe, 0xce, 0xf0,
12203 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12204 0x10, 0xfe, 0x22, 0x00,
12205 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12206 0x02, 0x65, 0xfe, 0xd0,
12207 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12208 0x0b, 0x10, 0x58, 0xfe,
12209 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12210 0x12, 0x00, 0x2c, 0x0f,
12211 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12212 0x0c, 0xbc, 0x17, 0x34,
12213 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12214 0x0c, 0x1c, 0x34, 0x94,
12215 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12216 0x4b, 0xfe, 0xdb, 0x10,
12217 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12218 0x89, 0xf0, 0x24, 0x33,
12219 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12220 0x33, 0x31, 0xdf, 0xbc,
12221 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12222 0x17, 0xfe, 0x2c, 0x0d,
12223 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12224 0x12, 0x55, 0xfe, 0x28,
12225 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12226 0x44, 0xfe, 0x28, 0x00,
12227 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12228 0x0f, 0x64, 0x12, 0x2f,
12229 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12230 0x0a, 0xfe, 0xb4, 0x10,
12231 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12232 0xfe, 0x34, 0x46, 0xac,
12233 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12234 0x37, 0x01, 0xf5, 0x01,
12235 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12236 0xfe, 0x2e, 0x03, 0x08,
12237 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12238 0x1a, 0xfe, 0x58, 0x12,
12239 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12240 0xfe, 0x50, 0x0d, 0xfe,
12241 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12242 0xfe, 0xa9, 0x10, 0x10,
12243 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12244 0xfe, 0x13, 0x00, 0xfe,
12245 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12246 0x24, 0x00, 0x8c, 0xb5,
12247 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12248 0xfe, 0x9d, 0x41, 0xfe,
12249 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12250 0xb4, 0x15, 0xfe, 0x31,
12251 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12252 0xec, 0xd0, 0xfc, 0x44,
12253 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12254 0x4b, 0x91, 0xfe, 0x75,
12255 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12256 0x0e, 0xfe, 0x44, 0x48,
12257 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12258 0xfe, 0x41, 0x58, 0x09,
12259 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12260 0x2e, 0x03, 0x09, 0x5d,
12261 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12262 0xce, 0x47, 0xfe, 0xad,
12263 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12264 0x59, 0x13, 0x9f, 0x13,
12265 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12266 0xe0, 0x0e, 0x0f, 0x06,
12267 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12268 0x3a, 0x01, 0x56, 0xfe,
12269 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12270 0x20, 0x4f, 0xfe, 0x05,
12271 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12272 0x48, 0xf4, 0x0d, 0xfe,
12273 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12274 0x15, 0x1a, 0x39, 0xa0,
12275 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12276 0x0c, 0xfe, 0x60, 0x01,
12277 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12278 0x06, 0x13, 0x2f, 0x12,
12279 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12280 0x22, 0x9f, 0xb7, 0x13,
12281 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12282 0xa0, 0xb4, 0xfe, 0xd9,
12283 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12284 0xc3, 0xfe, 0x03, 0xdc,
12285 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12286 0xfe, 0x00, 0xcc, 0x04,
12287 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12288 0xfe, 0x1c, 0x80, 0x07,
12289 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12290 0xfe, 0x0c, 0x90, 0xfe,
12291 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12292 0x0a, 0xfe, 0x3c, 0x50,
12293 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12294 0x16, 0x08, 0x05, 0x1b,
12295 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12296 0xfe, 0x2c, 0x13, 0x01,
12297 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12298 0x0c, 0xfe, 0x64, 0x01,
12299 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12300 0x80, 0x8d, 0xfe, 0x01,
12301 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12302 0x22, 0x20, 0xfb, 0x79,
12303 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12304 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012306 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12307 0xb2, 0x00, 0xfe, 0x09,
12308 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12309 0x45, 0x0f, 0x46, 0x52,
12310 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12311 0x0f, 0x44, 0x11, 0x0f,
12312 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12313 0x25, 0x11, 0x13, 0x20,
12314 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12315 0x56, 0xfe, 0xd6, 0xf0,
12316 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12317 0x18, 0x1c, 0x04, 0x42,
12318 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12319 0xf5, 0x13, 0x04, 0x01,
12320 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12321 0x13, 0x32, 0x07, 0x2f,
12322 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12323 0x41, 0x48, 0xfe, 0x45,
12324 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12325 0x07, 0x11, 0xac, 0x09,
12326 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12327 0x82, 0x4e, 0xfe, 0x14,
12328 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12329 0xfe, 0x01, 0xec, 0xa2,
12330 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12331 0x2a, 0x01, 0xe3, 0xfe,
12332 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12333 0xfe, 0x48, 0x12, 0x07,
12334 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12335 0xfe, 0x32, 0x12, 0x07,
12336 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12337 0x1f, 0xfe, 0x12, 0x12,
12338 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12339 0x94, 0x4b, 0x04, 0x2d,
12340 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12341 0x32, 0x07, 0xa6, 0xfe,
12342 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12343 0x5a, 0xfe, 0x72, 0x12,
12344 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12345 0xfe, 0x26, 0x13, 0x03,
12346 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12347 0x0c, 0x7f, 0x0c, 0x80,
12348 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12349 0x3c, 0xfe, 0x04, 0x55,
12350 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12351 0x91, 0x10, 0x03, 0x3f,
12352 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12353 0x88, 0x9b, 0x2e, 0x9c,
12354 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12355 0x56, 0x0c, 0x5e, 0x14,
12356 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12357 0x03, 0x60, 0x29, 0x61,
12358 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12359 0x50, 0xfe, 0xc6, 0x50,
12360 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12361 0x29, 0x3e, 0xfe, 0x40,
12362 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12363 0x2d, 0x01, 0x0b, 0x1d,
12364 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12365 0x72, 0x01, 0xaf, 0x1e,
12366 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12367 0x0a, 0x55, 0x35, 0xfe,
12368 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12369 0x02, 0x72, 0xfe, 0x19,
12370 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12371 0x1d, 0xe8, 0x33, 0x31,
12372 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12373 0x0b, 0x1c, 0x34, 0x1d,
12374 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12375 0x33, 0x31, 0xfe, 0xe8,
12376 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12377 0x05, 0x1f, 0x35, 0xa9,
12378 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12379 0x14, 0x01, 0xaf, 0x8c,
12380 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12381 0x03, 0x45, 0x28, 0x35,
12382 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12383 0x03, 0x5c, 0xc1, 0x0c,
12384 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12385 0x89, 0x01, 0x0b, 0x1c,
12386 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12387 0xfe, 0x42, 0x58, 0xf1,
12388 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12389 0xf4, 0x06, 0xea, 0x32,
12390 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12391 0x01, 0x0b, 0x26, 0x89,
12392 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12393 0x26, 0xfe, 0xd4, 0x13,
12394 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12395 0x13, 0x1c, 0xfe, 0xd0,
12396 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12397 0x0f, 0x71, 0xff, 0x02,
12398 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12399 0x00, 0x5c, 0x04, 0x0f,
12400 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12401 0xfe, 0x00, 0x5c, 0x04,
12402 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12403 0x02, 0x00, 0x57, 0x52,
12404 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12405 0x87, 0x04, 0xfe, 0x03,
12406 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12407 0xfe, 0x00, 0x7d, 0xfe,
12408 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12409 0x14, 0x5f, 0x57, 0x3f,
12410 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12411 0x5a, 0x8d, 0x04, 0x01,
12412 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12413 0xfe, 0x96, 0x15, 0x33,
12414 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12415 0x0a, 0xfe, 0xc1, 0x59,
12416 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12417 0x21, 0x69, 0x1a, 0xee,
12418 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12419 0x30, 0xfe, 0x78, 0x10,
12420 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12421 0x98, 0xfe, 0x30, 0x00,
12422 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12423 0x98, 0xfe, 0x64, 0x00,
12424 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12425 0x10, 0x69, 0x06, 0xfe,
12426 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12427 0x18, 0x59, 0x0f, 0x06,
12428 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12429 0x43, 0xf4, 0x9f, 0xfe,
12430 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12431 0x9e, 0xfe, 0xf3, 0x10,
12432 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12433 0x17, 0xfe, 0x4d, 0xe4,
12434 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12435 0x17, 0xfe, 0x4d, 0xe4,
12436 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12437 0xf4, 0x00, 0xe9, 0x91,
12438 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12439 0x04, 0x16, 0x06, 0x01,
12440 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12441 0x0b, 0x26, 0xf3, 0x76,
12442 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12443 0x16, 0x19, 0x01, 0x0b,
12444 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12445 0x0b, 0x26, 0xb1, 0x76,
12446 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12447 0xfe, 0x48, 0x13, 0xb8,
12448 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12449 0xec, 0xfe, 0x27, 0x01,
12450 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12451 0x07, 0xfe, 0xe3, 0x00,
12452 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12453 0x22, 0xd4, 0x07, 0x06,
12454 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12455 0x07, 0x11, 0xae, 0x09,
12456 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12457 0x0e, 0x8e, 0xfe, 0x80,
12458 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12459 0x09, 0x48, 0x01, 0x0e,
12460 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12461 0x80, 0xfe, 0x80, 0x4c,
12462 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12463 0x09, 0x5d, 0x01, 0x87,
12464 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12465 0x19, 0xde, 0xfe, 0x24,
12466 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12467 0x17, 0xad, 0x9a, 0x1b,
12468 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12469 0x16, 0xfe, 0xda, 0x10,
12470 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12471 0x18, 0x58, 0x03, 0xfe,
12472 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12473 0xf4, 0x06, 0xfe, 0x3c,
12474 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12475 0x97, 0xfe, 0x38, 0x17,
12476 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12477 0x10, 0x18, 0x11, 0x75,
12478 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12479 0x2e, 0x97, 0xfe, 0x5a,
12480 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12481 0xfe, 0x98, 0xe7, 0x00,
12482 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12483 0xfe, 0x30, 0xbc, 0xfe,
12484 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12485 0xcb, 0x97, 0xfe, 0x92,
12486 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12487 0x42, 0x10, 0xfe, 0x02,
12488 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12489 0x03, 0xa1, 0xfe, 0x1d,
12490 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12491 0x9a, 0x5b, 0x41, 0xfe,
12492 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12493 0x11, 0x12, 0xfe, 0xdd,
12494 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12495 0x17, 0x15, 0x06, 0x39,
12496 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12497 0xfe, 0x7e, 0x18, 0x1e,
12498 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12499 0x12, 0xfe, 0xe1, 0x10,
12500 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12501 0x13, 0x42, 0x92, 0x09,
12502 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12503 0xf0, 0xfe, 0x00, 0xcc,
12504 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12505 0x0e, 0xfe, 0x80, 0x4c,
12506 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12507 0x24, 0x12, 0xfe, 0x14,
12508 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12509 0xe7, 0x0a, 0x10, 0xfe,
12510 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12511 0x08, 0x54, 0x1b, 0x37,
12512 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12513 0x90, 0x3a, 0xce, 0x3b,
12514 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
12515 0x13, 0xa3, 0x04, 0x09,
12516 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
12517 0x44, 0x17, 0xfe, 0xe8,
12518 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
12519 0x5d, 0x01, 0xa8, 0x09,
12520 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
12521 0x1c, 0x19, 0x03, 0xfe,
12522 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
12523 0x6b, 0xfe, 0x2e, 0x19,
12524 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
12525 0xfe, 0x0b, 0x00, 0x6b,
12526 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
12527 0x08, 0x10, 0x03, 0xfe,
12528 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
12529 0x04, 0x68, 0x54, 0xe7,
12530 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
12531 0x1a, 0xf4, 0xfe, 0x00,
12532 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
12533 0x04, 0x07, 0x7e, 0xfe,
12534 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12535 0x07, 0x1a, 0xfe, 0x5a,
12536 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
12537 0x25, 0x6d, 0xe5, 0x07,
12538 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
12539 0xa9, 0xb8, 0x04, 0x15,
12540 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
12541 0x40, 0x5c, 0x04, 0x1c,
12542 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
12543 0xf7, 0xfe, 0x82, 0xf0,
12544 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012545};
12546
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012547static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
12548static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012549
12550/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012551static unsigned char _adv_asc38C1600_buf[] = {
12552 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
12553 0x18, 0xe4, 0x01, 0x00,
12554 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
12555 0x07, 0x17, 0xc0, 0x5f,
12556 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
12557 0x85, 0xf0, 0x86, 0xf0,
12558 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
12559 0x98, 0x57, 0x01, 0xe6,
12560 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
12561 0x38, 0x54, 0x32, 0xf0,
12562 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
12563 0x00, 0xe6, 0xb1, 0xf0,
12564 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
12565 0x06, 0x13, 0x0c, 0x1c,
12566 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
12567 0xb9, 0x54, 0x00, 0x80,
12568 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
12569 0x03, 0xe6, 0x01, 0xea,
12570 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
12571 0x04, 0x13, 0xbb, 0x55,
12572 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
12573 0xbb, 0x00, 0xc0, 0x00,
12574 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
12575 0x4c, 0x1c, 0x4e, 0x1c,
12576 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
12577 0x24, 0x01, 0x3c, 0x01,
12578 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
12579 0x78, 0x01, 0x7c, 0x01,
12580 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
12581 0x6e, 0x1e, 0x02, 0x48,
12582 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
12583 0x03, 0xfc, 0x06, 0x00,
12584 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
12585 0x30, 0x1c, 0x38, 0x1c,
12586 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
12587 0x5d, 0xf0, 0xa7, 0xf0,
12588 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
12589 0x33, 0x00, 0x34, 0x00,
12590 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
12591 0x79, 0x01, 0x3c, 0x09,
12592 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
12593 0x40, 0x16, 0x50, 0x16,
12594 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
12595 0x05, 0xf0, 0x09, 0xf0,
12596 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
12597 0x9c, 0x00, 0xa4, 0x00,
12598 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
12599 0xe9, 0x09, 0x5c, 0x0c,
12600 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
12601 0x42, 0x1d, 0x08, 0x44,
12602 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
12603 0x83, 0x55, 0x83, 0x59,
12604 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
12605 0x4b, 0xf4, 0x04, 0xf8,
12606 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
12607 0xa8, 0x00, 0xaa, 0x00,
12608 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
12609 0x7a, 0x01, 0x82, 0x01,
12610 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
12611 0x68, 0x08, 0x10, 0x0d,
12612 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
12613 0xf3, 0x10, 0x06, 0x12,
12614 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
12615 0xf0, 0x35, 0x05, 0xfe,
12616 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
12617 0xfe, 0x88, 0x01, 0xff,
12618 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12619 0x00, 0xfe, 0x57, 0x24,
12620 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
12621 0x00, 0x00, 0xff, 0x08,
12622 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12623 0xff, 0xff, 0xff, 0x13,
12624 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12625 0xfe, 0x04, 0xf7, 0xe8,
12626 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
12627 0x0d, 0x51, 0x37, 0xfe,
12628 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
12629 0xfe, 0xf8, 0x01, 0xfe,
12630 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
12631 0x05, 0xfe, 0x08, 0x0f,
12632 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
12633 0x28, 0x1c, 0x03, 0xfe,
12634 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
12635 0x48, 0xf0, 0xfe, 0x90,
12636 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
12637 0x02, 0xfe, 0x46, 0xf0,
12638 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
12639 0xfe, 0x4e, 0x02, 0xfe,
12640 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
12641 0x0d, 0xa2, 0x1c, 0x07,
12642 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
12643 0x1c, 0xf5, 0xfe, 0x1e,
12644 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
12645 0xde, 0x0a, 0x81, 0x01,
12646 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
12647 0x81, 0x01, 0x5c, 0xfe,
12648 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
12649 0xfe, 0x58, 0x1c, 0x1c,
12650 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
12651 0x2b, 0xfe, 0x9e, 0x02,
12652 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
12653 0x00, 0x47, 0xb8, 0x01,
12654 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
12655 0x1a, 0x31, 0xfe, 0x69,
12656 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
12657 0x1e, 0x1e, 0x20, 0x2c,
12658 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
12659 0x44, 0x15, 0x56, 0x51,
12660 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
12661 0x01, 0x18, 0x09, 0x00,
12662 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
12663 0x18, 0xfe, 0xc8, 0x54,
12664 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
12665 0xfe, 0x02, 0xe8, 0x30,
12666 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
12667 0xfe, 0xe4, 0x01, 0xfe,
12668 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
12669 0x26, 0xf0, 0xfe, 0x66,
12670 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
12671 0xef, 0x10, 0xfe, 0x9f,
12672 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
12673 0x70, 0x37, 0xfe, 0x48,
12674 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
12675 0x21, 0xb9, 0xc7, 0x20,
12676 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
12677 0xe1, 0x2a, 0xeb, 0xfe,
12678 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
12679 0x15, 0xfe, 0xe4, 0x00,
12680 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
12681 0xfe, 0x06, 0xf0, 0xfe,
12682 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
12683 0x03, 0x81, 0x1e, 0x1b,
12684 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
12685 0xea, 0xfe, 0x46, 0x1c,
12686 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12687 0xfe, 0x48, 0x1c, 0x75,
12688 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
12689 0xe1, 0x01, 0x18, 0x77,
12690 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
12691 0x8f, 0xfe, 0x70, 0x02,
12692 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
12693 0x16, 0xfe, 0x4a, 0x04,
12694 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
12695 0x02, 0x00, 0x10, 0x01,
12696 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
12697 0xee, 0xfe, 0x4c, 0x44,
12698 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
12699 0x7b, 0xec, 0x60, 0x8d,
12700 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
12701 0x0c, 0x06, 0x28, 0xfe,
12702 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
12703 0x13, 0x34, 0xfe, 0x4c,
12704 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
12705 0x13, 0x01, 0x0c, 0x06,
12706 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
12707 0x28, 0xf9, 0x1f, 0x7f,
12708 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
12709 0xfe, 0xa4, 0x0e, 0x05,
12710 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
12711 0x9c, 0x93, 0x3a, 0x0b,
12712 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
12713 0x7d, 0x1d, 0xfe, 0x46,
12714 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
12715 0xfe, 0x87, 0x83, 0xfe,
12716 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
12717 0x13, 0x0f, 0xfe, 0x20,
12718 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
12719 0x12, 0x01, 0x38, 0x06,
12720 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
12721 0x05, 0xd0, 0x54, 0x01,
12722 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
12723 0x50, 0x12, 0x5e, 0xff,
12724 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
12725 0x00, 0x10, 0x2f, 0xfe,
12726 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
12727 0x38, 0xfe, 0x4a, 0xf0,
12728 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
12729 0x21, 0x00, 0xf1, 0x2e,
12730 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
12731 0x10, 0x2f, 0xfe, 0xd0,
12732 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
12733 0x1c, 0x00, 0x4d, 0x01,
12734 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
12735 0x28, 0xfe, 0x24, 0x12,
12736 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
12737 0x0d, 0x00, 0x01, 0x42,
12738 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
12739 0x03, 0xb6, 0x1e, 0xfe,
12740 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
12741 0xfe, 0x72, 0x06, 0x0a,
12742 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
12743 0x19, 0x16, 0xfe, 0x68,
12744 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
12745 0x03, 0x9a, 0x1e, 0xfe,
12746 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
12747 0x48, 0xfe, 0x92, 0x06,
12748 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
12749 0x58, 0xff, 0x02, 0x00,
12750 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
12751 0xfe, 0xea, 0x06, 0x01,
12752 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
12753 0xfe, 0xe0, 0x06, 0x15,
12754 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
12755 0x01, 0x84, 0xfe, 0xae,
12756 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
12757 0x1e, 0xfe, 0x1a, 0x12,
12758 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
12759 0x43, 0x48, 0x62, 0x80,
12760 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
12761 0x36, 0xfe, 0x02, 0xf6,
12762 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
12763 0xd0, 0x0d, 0x17, 0xfe,
12764 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
12765 0x9e, 0x15, 0x82, 0x01,
12766 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
12767 0x57, 0x10, 0xe6, 0x05,
12768 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
12769 0xfe, 0x9c, 0x32, 0x5f,
12770 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
12771 0xfe, 0x0a, 0xf0, 0xfe,
12772 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
12773 0xaf, 0xa0, 0x05, 0x29,
12774 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
12775 0x00, 0x01, 0x08, 0x14,
12776 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
12777 0x14, 0x00, 0x05, 0xfe,
12778 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
12779 0x12, 0xfe, 0x30, 0x13,
12780 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
12781 0x01, 0x08, 0x14, 0x00,
12782 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
12783 0x78, 0x4f, 0x0f, 0xfe,
12784 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
12785 0x28, 0x48, 0xfe, 0x6c,
12786 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
12787 0x12, 0x53, 0x63, 0x4e,
12788 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
12789 0x6c, 0x08, 0xaf, 0xa0,
12790 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
12791 0x05, 0xed, 0xfe, 0x9c,
12792 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
12793 0x1e, 0xfe, 0x99, 0x58,
12794 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
12795 0x22, 0x6b, 0x01, 0x0c,
12796 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
12797 0x1e, 0x47, 0x2c, 0x7a,
12798 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
12799 0x01, 0x0c, 0x61, 0x65,
12800 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
12801 0x16, 0xfe, 0x08, 0x50,
12802 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
12803 0x01, 0xfe, 0xce, 0x1e,
12804 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
12805 0x01, 0xfe, 0xfe, 0x1e,
12806 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
12807 0x10, 0x01, 0x0c, 0x06,
12808 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
12809 0x10, 0x6a, 0x22, 0x6b,
12810 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
12811 0xfe, 0x9f, 0x83, 0x33,
12812 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
12813 0x3a, 0x0b, 0xfe, 0xc6,
12814 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
12815 0x01, 0xfe, 0xce, 0x1e,
12816 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
12817 0x04, 0xfe, 0xc0, 0x93,
12818 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
12819 0x10, 0x4b, 0x22, 0x4c,
12820 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
12821 0x4e, 0x11, 0x2f, 0xfe,
12822 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
12823 0x3c, 0x37, 0x88, 0xf5,
12824 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
12825 0xd3, 0xfe, 0x42, 0x0a,
12826 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
12827 0x05, 0x29, 0x01, 0x41,
12828 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
12829 0xfe, 0x14, 0x12, 0x01,
12830 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
12831 0x2e, 0x1c, 0x05, 0xfe,
12832 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
12833 0xfe, 0x2c, 0x1c, 0xfe,
12834 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
12835 0x92, 0x10, 0xc4, 0xf6,
12836 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
12837 0xe7, 0x10, 0xfe, 0x2b,
12838 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
12839 0xac, 0xfe, 0xd2, 0xf0,
12840 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
12841 0x1b, 0xbf, 0xd4, 0x5b,
12842 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
12843 0x5e, 0x32, 0x1f, 0x7f,
12844 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
12845 0x05, 0x70, 0xfe, 0x74,
12846 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
12847 0x0f, 0x4d, 0x01, 0xfe,
12848 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
12849 0x0d, 0x2b, 0xfe, 0xe2,
12850 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
12851 0xfe, 0x88, 0x13, 0x21,
12852 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
12853 0x83, 0x83, 0xfe, 0xc9,
12854 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
12855 0x91, 0x04, 0xfe, 0x84,
12856 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
12857 0xfe, 0xcb, 0x57, 0x0b,
12858 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
12859 0x6a, 0x3b, 0x6b, 0x10,
12860 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
12861 0x20, 0x6e, 0xdb, 0x64,
12862 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
12863 0xfe, 0x04, 0xfa, 0x64,
12864 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
12865 0x10, 0x98, 0x91, 0x6c,
12866 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
12867 0x4b, 0x7e, 0x4c, 0x01,
12868 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
12869 0x58, 0xfe, 0x91, 0x58,
12870 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
12871 0x1b, 0x40, 0x01, 0x0c,
12872 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
12873 0xfe, 0x10, 0x90, 0x04,
12874 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
12875 0x79, 0x0b, 0x0e, 0xfe,
12876 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
12877 0x01, 0x0c, 0x06, 0x0d,
12878 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
12879 0x0c, 0x58, 0xfe, 0x8d,
12880 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
12881 0x83, 0x33, 0x0b, 0x0e,
12882 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
12883 0x19, 0xfe, 0x19, 0x41,
12884 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
12885 0x19, 0xfe, 0x44, 0x00,
12886 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
12887 0x4c, 0xfe, 0x0c, 0x51,
12888 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
12889 0x76, 0x10, 0xac, 0xfe,
12890 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
12891 0xe3, 0x23, 0x07, 0xfe,
12892 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
12893 0xcc, 0x0c, 0x1f, 0x92,
12894 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
12895 0x0c, 0xfe, 0x3e, 0x10,
12896 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
12897 0xfe, 0xcb, 0xf0, 0xfe,
12898 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
12899 0xf4, 0x0c, 0x19, 0x94,
12900 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
12901 0xfe, 0xcc, 0xf0, 0xef,
12902 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
12903 0x4e, 0x11, 0x2f, 0xfe,
12904 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
12905 0x3c, 0x37, 0x88, 0xf5,
12906 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
12907 0x2f, 0xfe, 0x3e, 0x0d,
12908 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
12909 0xd2, 0x9f, 0xd3, 0x9f,
12910 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
12911 0xc5, 0x75, 0xd7, 0x99,
12912 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
12913 0x9c, 0x2f, 0xfe, 0x8c,
12914 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
12915 0x42, 0x00, 0x05, 0x70,
12916 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
12917 0x0d, 0xfe, 0x44, 0x13,
12918 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
12919 0xfe, 0xda, 0x0e, 0x0a,
12920 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
12921 0x10, 0x01, 0xfe, 0xf4,
12922 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
12923 0x15, 0x56, 0x01, 0x85,
12924 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
12925 0xcc, 0x10, 0x01, 0xa7,
12926 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
12927 0xfe, 0x99, 0x83, 0xfe,
12928 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
12929 0x43, 0x00, 0xfe, 0xa2,
12930 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
12931 0x00, 0x1d, 0x40, 0x15,
12932 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
12933 0xfe, 0x3a, 0x03, 0x01,
12934 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
12935 0x76, 0x06, 0x12, 0xfe,
12936 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
12937 0xfe, 0x9d, 0xf0, 0xfe,
12938 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
12939 0x0c, 0x61, 0x12, 0x44,
12940 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
12941 0xfe, 0x2e, 0x10, 0x19,
12942 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
12943 0xfe, 0x41, 0x00, 0xa2,
12944 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
12945 0xea, 0x4f, 0xfe, 0x04,
12946 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
12947 0x35, 0xfe, 0x12, 0x1c,
12948 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
12949 0xfe, 0xd4, 0x11, 0x05,
12950 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
12951 0xce, 0x45, 0x31, 0x51,
12952 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
12953 0x67, 0xfe, 0x98, 0x56,
12954 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
12955 0x0c, 0x06, 0x28, 0xfe,
12956 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
12957 0xfe, 0xfa, 0x14, 0xfe,
12958 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
12959 0xfe, 0xe0, 0x14, 0xfe,
12960 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
12961 0xfe, 0xad, 0x13, 0x05,
12962 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
12963 0xe7, 0xfe, 0x08, 0x1c,
12964 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
12965 0x48, 0x55, 0xa5, 0x3b,
12966 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
12967 0xf0, 0x1a, 0x03, 0xfe,
12968 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
12969 0xec, 0xe7, 0x53, 0x00,
12970 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
12971 0x01, 0xfe, 0x62, 0x1b,
12972 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
12973 0xea, 0xe7, 0x53, 0x92,
12974 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
12975 0xfe, 0x38, 0x01, 0x23,
12976 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
12977 0x01, 0x01, 0xfe, 0x1e,
12978 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
12979 0x26, 0x02, 0x21, 0x96,
12980 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
12981 0xc3, 0xfe, 0xe1, 0x10,
12982 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
12983 0xfe, 0x03, 0xdc, 0xfe,
12984 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
12985 0x00, 0xcc, 0x02, 0xfe,
12986 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
12987 0x0f, 0xfe, 0x1c, 0x80,
12988 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
12989 0x0f, 0xfe, 0x1e, 0x80,
12990 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
12991 0x1d, 0x80, 0x04, 0xfe,
12992 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
12993 0x1e, 0xac, 0xfe, 0x14,
12994 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
12995 0x1f, 0xfe, 0x30, 0xf4,
12996 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
12997 0x56, 0xfb, 0x01, 0xfe,
12998 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
12999 0xfe, 0x00, 0x1d, 0x15,
13000 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
13001 0x22, 0x1b, 0xfe, 0x1e,
13002 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
13003 0x96, 0x90, 0x04, 0xfe,
13004 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
13005 0x01, 0x01, 0x0c, 0x06,
13006 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
13007 0x0e, 0x77, 0xfe, 0x01,
13008 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
13009 0x21, 0x2c, 0xfe, 0x00,
13010 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
13011 0x06, 0x58, 0x03, 0xfe,
13012 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
13013 0x03, 0xfe, 0xb2, 0x00,
13014 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
13015 0x66, 0x10, 0x55, 0x10,
13016 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
13017 0x54, 0x2b, 0xfe, 0x88,
13018 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
13019 0x91, 0x54, 0x2b, 0xfe,
13020 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
13021 0x00, 0x40, 0x8d, 0x2c,
13022 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
13023 0x12, 0x1c, 0x75, 0xfe,
13024 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
13025 0x14, 0xfe, 0x0e, 0x47,
13026 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
13027 0xa7, 0x90, 0x34, 0x60,
13028 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
13029 0x09, 0x56, 0xfe, 0x34,
13030 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
13031 0xfe, 0x45, 0x48, 0x01,
13032 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
13033 0x09, 0x1a, 0xa5, 0x0a,
13034 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
13035 0xfe, 0x14, 0x56, 0xfe,
13036 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
13037 0xec, 0xb8, 0xfe, 0x9e,
13038 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
13039 0xf4, 0xfe, 0xdd, 0x10,
13040 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
13041 0x12, 0x09, 0x0d, 0xfe,
13042 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
13043 0x13, 0x09, 0xfe, 0x23,
13044 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
13045 0x24, 0xfe, 0x12, 0x12,
13046 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
13047 0xae, 0x41, 0x02, 0x32,
13048 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
13049 0x35, 0x32, 0x01, 0x43,
13050 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
13051 0x13, 0x01, 0x0c, 0x06,
13052 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
13053 0xe5, 0x55, 0xb0, 0xfe,
13054 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
13055 0xfe, 0xb6, 0x0e, 0x10,
13056 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
13057 0x88, 0x20, 0x6e, 0x01,
13058 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
13059 0x55, 0xfe, 0x04, 0xfa,
13060 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
13061 0xfe, 0x40, 0x56, 0xfe,
13062 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
13063 0x44, 0x55, 0xfe, 0xe5,
13064 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
13065 0x68, 0x22, 0x69, 0x01,
13066 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
13067 0x6b, 0xfe, 0x2c, 0x50,
13068 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
13069 0x50, 0x03, 0x68, 0x3b,
13070 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
13071 0x40, 0x50, 0xfe, 0xc2,
13072 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
13073 0x16, 0x3d, 0x27, 0x25,
13074 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
13075 0xa6, 0x23, 0x3f, 0x1b,
13076 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
13077 0xfe, 0x0a, 0x55, 0x31,
13078 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
13079 0x51, 0x05, 0x72, 0x01,
13080 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
13081 0x2a, 0x3c, 0x16, 0xc0,
13082 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
13083 0xfe, 0x66, 0x15, 0x05,
13084 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
13085 0x2b, 0x3d, 0x01, 0x08,
13086 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
13087 0xb6, 0x1e, 0x83, 0x01,
13088 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
13089 0x07, 0x90, 0x3f, 0x01,
13090 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
13091 0x01, 0x43, 0x09, 0x82,
13092 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
13093 0x05, 0x72, 0xfe, 0xc0,
13094 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
13095 0x32, 0x01, 0x08, 0x17,
13096 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
13097 0x3d, 0x27, 0x25, 0xbd,
13098 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
13099 0xe8, 0x14, 0x01, 0xa6,
13100 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
13101 0x0e, 0x12, 0x01, 0x43,
13102 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
13103 0x01, 0x08, 0x17, 0x73,
13104 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
13105 0x27, 0x25, 0xbd, 0x09,
13106 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
13107 0xb6, 0x14, 0x86, 0xa8,
13108 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
13109 0x82, 0x4e, 0x05, 0x72,
13110 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
13111 0xfe, 0xc0, 0x19, 0x05,
13112 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
13113 0xcc, 0x01, 0x08, 0x26,
13114 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
13115 0xcc, 0x15, 0x5e, 0x32,
13116 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
13117 0xad, 0x23, 0xfe, 0xff,
13118 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
13119 0x00, 0x57, 0x52, 0xad,
13120 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
13121 0x02, 0x00, 0x57, 0x52,
13122 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
13123 0x02, 0x13, 0x58, 0xff,
13124 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
13125 0x5c, 0x0a, 0x55, 0x01,
13126 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
13127 0xff, 0x03, 0x00, 0x54,
13128 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
13129 0x7c, 0x3a, 0x0b, 0x0e,
13130 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
13131 0xfe, 0x1a, 0xf7, 0x00,
13132 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
13133 0xda, 0x6d, 0x02, 0xfe,
13134 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
13135 0x02, 0x01, 0xc6, 0xfe,
13136 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
13137 0x25, 0xbe, 0x01, 0x08,
13138 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
13139 0x03, 0x9a, 0x1e, 0xfe,
13140 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
13141 0x48, 0xfe, 0x08, 0x17,
13142 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
13143 0x17, 0x4d, 0x13, 0x07,
13144 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
13145 0xff, 0x02, 0x83, 0x55,
13146 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
13147 0x17, 0x1c, 0x63, 0x13,
13148 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
13149 0x00, 0xb0, 0xfe, 0x80,
13150 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
13151 0x53, 0x07, 0xfe, 0x60,
13152 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
13153 0x00, 0x1c, 0x95, 0x13,
13154 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
13155 0xfe, 0x43, 0xf4, 0x96,
13156 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
13157 0xf4, 0x94, 0xf6, 0x8b,
13158 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
13159 0xda, 0x17, 0x62, 0x49,
13160 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
13161 0x71, 0x50, 0x26, 0xfe,
13162 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
13163 0x58, 0x02, 0x50, 0x13,
13164 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
13165 0x25, 0xbe, 0xfe, 0x03,
13166 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
13167 0x0a, 0x01, 0x08, 0x16,
13168 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13169 0x01, 0x08, 0x16, 0xa9,
13170 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13171 0x08, 0x16, 0xa9, 0x27,
13172 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13173 0x01, 0x38, 0x06, 0x24,
13174 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13175 0x78, 0x03, 0x9a, 0x1e,
13176 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13177 0xfe, 0x40, 0x5a, 0x23,
13178 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13179 0x80, 0x48, 0xfe, 0xaa,
13180 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13181 0xfe, 0xac, 0x1d, 0xfe,
13182 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13183 0x43, 0x48, 0x2d, 0x93,
13184 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13185 0x36, 0xfe, 0x34, 0xf4,
13186 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13187 0x28, 0x10, 0xfe, 0xc0,
13188 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13189 0x18, 0x45, 0xfe, 0x1c,
13190 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13191 0x19, 0xfe, 0x04, 0xf4,
13192 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13193 0x21, 0xfe, 0x7f, 0x01,
13194 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13195 0x7e, 0x01, 0xfe, 0xc8,
13196 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13197 0x21, 0xfe, 0x81, 0x01,
13198 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13199 0x13, 0x0d, 0x02, 0x14,
13200 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13201 0xfe, 0x82, 0x19, 0x14,
13202 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13203 0x08, 0x02, 0x14, 0x07,
13204 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13205 0x01, 0x08, 0x17, 0xc1,
13206 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13207 0x08, 0x02, 0x50, 0x02,
13208 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13209 0x14, 0x12, 0x01, 0x08,
13210 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13211 0x08, 0x17, 0x74, 0xfe,
13212 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13213 0x74, 0x5f, 0xcc, 0x01,
13214 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13215 0xfe, 0x49, 0xf4, 0x00,
13216 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13217 0x02, 0x00, 0x10, 0x2f,
13218 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13219 0x16, 0xfe, 0x64, 0x1a,
13220 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13221 0x61, 0x07, 0x44, 0x02,
13222 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13223 0x13, 0x0a, 0x9d, 0x01,
13224 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13225 0xfe, 0x80, 0xe7, 0x1a,
13226 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13227 0x0a, 0x5a, 0x01, 0x18,
13228 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13229 0x7e, 0x1e, 0xfe, 0x80,
13230 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13231 0xfe, 0x80, 0x4c, 0x0a,
13232 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13233 0xfe, 0x19, 0xde, 0xfe,
13234 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13235 0x2a, 0x1c, 0xfa, 0xb3,
13236 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13237 0xf4, 0x1a, 0xfe, 0xfa,
13238 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13239 0xfe, 0x18, 0x58, 0x03,
13240 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13241 0xfe, 0x30, 0xf4, 0x07,
13242 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13243 0xf7, 0x24, 0xb1, 0xfe,
13244 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13245 0xfe, 0xba, 0x10, 0x1c,
13246 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13247 0x1d, 0xf7, 0x54, 0xb1,
13248 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13249 0xaf, 0x19, 0xfe, 0x98,
13250 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13251 0x1a, 0x87, 0x8b, 0x0f,
13252 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13253 0xfe, 0x32, 0x90, 0x04,
13254 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13255 0x7c, 0x12, 0xfe, 0x0f,
13256 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13257 0x31, 0x02, 0xc9, 0x2b,
13258 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13259 0x6a, 0xfe, 0x19, 0xfe,
13260 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13261 0x1b, 0xfe, 0x36, 0x14,
13262 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13263 0xfe, 0x80, 0xe7, 0x1a,
13264 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13265 0x30, 0xfe, 0x12, 0x45,
13266 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13267 0x39, 0xf0, 0x75, 0x26,
13268 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13269 0xe3, 0x23, 0x07, 0xfe,
13270 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13271 0x56, 0xfe, 0x3c, 0x13,
13272 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13273 0x01, 0x18, 0xcb, 0xfe,
13274 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13275 0xfe, 0x00, 0xcc, 0xcb,
13276 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13277 0xfe, 0x80, 0x4c, 0x01,
13278 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13279 0x12, 0xfe, 0x14, 0x56,
13280 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13281 0x0d, 0x19, 0xfe, 0x15,
13282 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13283 0x83, 0xfe, 0x18, 0x80,
13284 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13285 0x90, 0xfe, 0xba, 0x90,
13286 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13287 0x21, 0xb9, 0x88, 0x20,
13288 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13289 0x18, 0xfe, 0x49, 0x44,
13290 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13291 0x1a, 0xa4, 0x0a, 0x67,
13292 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13293 0x1d, 0x7b, 0xfe, 0x52,
13294 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13295 0x4e, 0xe4, 0xdd, 0x7b,
13296 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13297 0xfe, 0x4e, 0xe4, 0xfe,
13298 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13299 0xfe, 0x08, 0x10, 0x03,
13300 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13301 0x68, 0x54, 0xfe, 0xf1,
13302 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13303 0xfe, 0x1a, 0xf4, 0xfe,
13304 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13305 0x09, 0x92, 0xfe, 0x5a,
13306 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13307 0x5a, 0xf0, 0xfe, 0xc8,
13308 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13309 0x1a, 0x10, 0x09, 0x0d,
13310 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13311 0x1f, 0x93, 0x01, 0x42,
13312 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13313 0xfe, 0x14, 0xf0, 0x08,
13314 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13315 0xfe, 0x82, 0xf0, 0xfe,
13316 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13317 0x02, 0x0f, 0xfe, 0x18,
13318 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13319 0x80, 0x04, 0xfe, 0x82,
13320 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13321 0x83, 0x33, 0x0b, 0x0e,
13322 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13323 0x02, 0x0f, 0xfe, 0x04,
13324 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13325 0x80, 0x04, 0xfe, 0x80,
13326 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13327 0xfe, 0x99, 0x83, 0xfe,
13328 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13329 0x83, 0xfe, 0xce, 0x47,
13330 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13331 0x0b, 0x0e, 0x02, 0x0f,
13332 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13333 0xfe, 0x08, 0x90, 0x04,
13334 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13335 0xfe, 0x8a, 0x93, 0x79,
13336 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13337 0x0b, 0x0e, 0x02, 0x0f,
13338 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13339 0xfe, 0x3c, 0x90, 0x04,
13340 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13341 0x04, 0xfe, 0x83, 0x83,
13342 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013343};
13344
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013345static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13346static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013347
13348/* a_init.c */
13349/*
13350 * EEPROM Configuration.
13351 *
13352 * All drivers should use this structure to set the default EEPROM
13353 * configuration. The BIOS now uses this structure when it is built.
13354 * Additional structure information can be found in a_condor.h where
13355 * the structure is defined.
13356 *
13357 * The *_Field_IsChar structs are needed to correct for endianness.
13358 * These values are read from the board 16 bits at a time directly
13359 * into the structs. Because some fields are char, the values will be
13360 * in the wrong order. The *_Field_IsChar tells when to flip the
13361 * bytes. Data read and written to PCI memory is automatically swapped
13362 * on big-endian platforms so char fields read as words are actually being
13363 * unswapped on big-endian platforms.
13364 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013365static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013366 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13367 0x0000, /* cfg_msw */
13368 0xFFFF, /* disc_enable */
13369 0xFFFF, /* wdtr_able */
13370 0xFFFF, /* sdtr_able */
13371 0xFFFF, /* start_motor */
13372 0xFFFF, /* tagqng_able */
13373 0xFFFF, /* bios_scan */
13374 0, /* scam_tolerant */
13375 7, /* adapter_scsi_id */
13376 0, /* bios_boot_delay */
13377 3, /* scsi_reset_delay */
13378 0, /* bios_id_lun */
13379 0, /* termination */
13380 0, /* reserved1 */
13381 0xFFE7, /* bios_ctrl */
13382 0xFFFF, /* ultra_able */
13383 0, /* reserved2 */
13384 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13385 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13386 0, /* dvc_cntl */
13387 0, /* bug_fix */
13388 0, /* serial_number_word1 */
13389 0, /* serial_number_word2 */
13390 0, /* serial_number_word3 */
13391 0, /* check_sum */
13392 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13393 , /* oem_name[16] */
13394 0, /* dvc_err_code */
13395 0, /* adv_err_code */
13396 0, /* adv_err_addr */
13397 0, /* saved_dvc_err_code */
13398 0, /* saved_adv_err_code */
13399 0, /* saved_adv_err_addr */
13400 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013401};
13402
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013403static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013404 0, /* cfg_lsw */
13405 0, /* cfg_msw */
13406 0, /* -disc_enable */
13407 0, /* wdtr_able */
13408 0, /* sdtr_able */
13409 0, /* start_motor */
13410 0, /* tagqng_able */
13411 0, /* bios_scan */
13412 0, /* scam_tolerant */
13413 1, /* adapter_scsi_id */
13414 1, /* bios_boot_delay */
13415 1, /* scsi_reset_delay */
13416 1, /* bios_id_lun */
13417 1, /* termination */
13418 1, /* reserved1 */
13419 0, /* bios_ctrl */
13420 0, /* ultra_able */
13421 0, /* reserved2 */
13422 1, /* max_host_qng */
13423 1, /* max_dvc_qng */
13424 0, /* dvc_cntl */
13425 0, /* bug_fix */
13426 0, /* serial_number_word1 */
13427 0, /* serial_number_word2 */
13428 0, /* serial_number_word3 */
13429 0, /* check_sum */
13430 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13431 , /* oem_name[16] */
13432 0, /* dvc_err_code */
13433 0, /* adv_err_code */
13434 0, /* adv_err_addr */
13435 0, /* saved_dvc_err_code */
13436 0, /* saved_adv_err_code */
13437 0, /* saved_adv_err_addr */
13438 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013439};
13440
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013441static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013442 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13443 0x0000, /* 01 cfg_msw */
13444 0xFFFF, /* 02 disc_enable */
13445 0xFFFF, /* 03 wdtr_able */
13446 0x4444, /* 04 sdtr_speed1 */
13447 0xFFFF, /* 05 start_motor */
13448 0xFFFF, /* 06 tagqng_able */
13449 0xFFFF, /* 07 bios_scan */
13450 0, /* 08 scam_tolerant */
13451 7, /* 09 adapter_scsi_id */
13452 0, /* bios_boot_delay */
13453 3, /* 10 scsi_reset_delay */
13454 0, /* bios_id_lun */
13455 0, /* 11 termination_se */
13456 0, /* termination_lvd */
13457 0xFFE7, /* 12 bios_ctrl */
13458 0x4444, /* 13 sdtr_speed2 */
13459 0x4444, /* 14 sdtr_speed3 */
13460 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13461 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13462 0, /* 16 dvc_cntl */
13463 0x4444, /* 17 sdtr_speed4 */
13464 0, /* 18 serial_number_word1 */
13465 0, /* 19 serial_number_word2 */
13466 0, /* 20 serial_number_word3 */
13467 0, /* 21 check_sum */
13468 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13469 , /* 22-29 oem_name[16] */
13470 0, /* 30 dvc_err_code */
13471 0, /* 31 adv_err_code */
13472 0, /* 32 adv_err_addr */
13473 0, /* 33 saved_dvc_err_code */
13474 0, /* 34 saved_adv_err_code */
13475 0, /* 35 saved_adv_err_addr */
13476 0, /* 36 reserved */
13477 0, /* 37 reserved */
13478 0, /* 38 reserved */
13479 0, /* 39 reserved */
13480 0, /* 40 reserved */
13481 0, /* 41 reserved */
13482 0, /* 42 reserved */
13483 0, /* 43 reserved */
13484 0, /* 44 reserved */
13485 0, /* 45 reserved */
13486 0, /* 46 reserved */
13487 0, /* 47 reserved */
13488 0, /* 48 reserved */
13489 0, /* 49 reserved */
13490 0, /* 50 reserved */
13491 0, /* 51 reserved */
13492 0, /* 52 reserved */
13493 0, /* 53 reserved */
13494 0, /* 54 reserved */
13495 0, /* 55 reserved */
13496 0, /* 56 cisptr_lsw */
13497 0, /* 57 cisprt_msw */
13498 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13499 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13500 0, /* 60 reserved */
13501 0, /* 61 reserved */
13502 0, /* 62 reserved */
13503 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013504};
13505
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013506static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013507 0, /* 00 cfg_lsw */
13508 0, /* 01 cfg_msw */
13509 0, /* 02 disc_enable */
13510 0, /* 03 wdtr_able */
13511 0, /* 04 sdtr_speed1 */
13512 0, /* 05 start_motor */
13513 0, /* 06 tagqng_able */
13514 0, /* 07 bios_scan */
13515 0, /* 08 scam_tolerant */
13516 1, /* 09 adapter_scsi_id */
13517 1, /* bios_boot_delay */
13518 1, /* 10 scsi_reset_delay */
13519 1, /* bios_id_lun */
13520 1, /* 11 termination_se */
13521 1, /* termination_lvd */
13522 0, /* 12 bios_ctrl */
13523 0, /* 13 sdtr_speed2 */
13524 0, /* 14 sdtr_speed3 */
13525 1, /* 15 max_host_qng */
13526 1, /* max_dvc_qng */
13527 0, /* 16 dvc_cntl */
13528 0, /* 17 sdtr_speed4 */
13529 0, /* 18 serial_number_word1 */
13530 0, /* 19 serial_number_word2 */
13531 0, /* 20 serial_number_word3 */
13532 0, /* 21 check_sum */
13533 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13534 , /* 22-29 oem_name[16] */
13535 0, /* 30 dvc_err_code */
13536 0, /* 31 adv_err_code */
13537 0, /* 32 adv_err_addr */
13538 0, /* 33 saved_dvc_err_code */
13539 0, /* 34 saved_adv_err_code */
13540 0, /* 35 saved_adv_err_addr */
13541 0, /* 36 reserved */
13542 0, /* 37 reserved */
13543 0, /* 38 reserved */
13544 0, /* 39 reserved */
13545 0, /* 40 reserved */
13546 0, /* 41 reserved */
13547 0, /* 42 reserved */
13548 0, /* 43 reserved */
13549 0, /* 44 reserved */
13550 0, /* 45 reserved */
13551 0, /* 46 reserved */
13552 0, /* 47 reserved */
13553 0, /* 48 reserved */
13554 0, /* 49 reserved */
13555 0, /* 50 reserved */
13556 0, /* 51 reserved */
13557 0, /* 52 reserved */
13558 0, /* 53 reserved */
13559 0, /* 54 reserved */
13560 0, /* 55 reserved */
13561 0, /* 56 cisptr_lsw */
13562 0, /* 57 cisprt_msw */
13563 0, /* 58 subsysvid */
13564 0, /* 59 subsysid */
13565 0, /* 60 reserved */
13566 0, /* 61 reserved */
13567 0, /* 62 reserved */
13568 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013569};
13570
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013571static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013572 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13573 0x0000, /* 01 cfg_msw */
13574 0xFFFF, /* 02 disc_enable */
13575 0xFFFF, /* 03 wdtr_able */
13576 0x5555, /* 04 sdtr_speed1 */
13577 0xFFFF, /* 05 start_motor */
13578 0xFFFF, /* 06 tagqng_able */
13579 0xFFFF, /* 07 bios_scan */
13580 0, /* 08 scam_tolerant */
13581 7, /* 09 adapter_scsi_id */
13582 0, /* bios_boot_delay */
13583 3, /* 10 scsi_reset_delay */
13584 0, /* bios_id_lun */
13585 0, /* 11 termination_se */
13586 0, /* termination_lvd */
13587 0xFFE7, /* 12 bios_ctrl */
13588 0x5555, /* 13 sdtr_speed2 */
13589 0x5555, /* 14 sdtr_speed3 */
13590 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13591 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13592 0, /* 16 dvc_cntl */
13593 0x5555, /* 17 sdtr_speed4 */
13594 0, /* 18 serial_number_word1 */
13595 0, /* 19 serial_number_word2 */
13596 0, /* 20 serial_number_word3 */
13597 0, /* 21 check_sum */
13598 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13599 , /* 22-29 oem_name[16] */
13600 0, /* 30 dvc_err_code */
13601 0, /* 31 adv_err_code */
13602 0, /* 32 adv_err_addr */
13603 0, /* 33 saved_dvc_err_code */
13604 0, /* 34 saved_adv_err_code */
13605 0, /* 35 saved_adv_err_addr */
13606 0, /* 36 reserved */
13607 0, /* 37 reserved */
13608 0, /* 38 reserved */
13609 0, /* 39 reserved */
13610 0, /* 40 reserved */
13611 0, /* 41 reserved */
13612 0, /* 42 reserved */
13613 0, /* 43 reserved */
13614 0, /* 44 reserved */
13615 0, /* 45 reserved */
13616 0, /* 46 reserved */
13617 0, /* 47 reserved */
13618 0, /* 48 reserved */
13619 0, /* 49 reserved */
13620 0, /* 50 reserved */
13621 0, /* 51 reserved */
13622 0, /* 52 reserved */
13623 0, /* 53 reserved */
13624 0, /* 54 reserved */
13625 0, /* 55 reserved */
13626 0, /* 56 cisptr_lsw */
13627 0, /* 57 cisprt_msw */
13628 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13629 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
13630 0, /* 60 reserved */
13631 0, /* 61 reserved */
13632 0, /* 62 reserved */
13633 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013634};
13635
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013636static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013637 0, /* 00 cfg_lsw */
13638 0, /* 01 cfg_msw */
13639 0, /* 02 disc_enable */
13640 0, /* 03 wdtr_able */
13641 0, /* 04 sdtr_speed1 */
13642 0, /* 05 start_motor */
13643 0, /* 06 tagqng_able */
13644 0, /* 07 bios_scan */
13645 0, /* 08 scam_tolerant */
13646 1, /* 09 adapter_scsi_id */
13647 1, /* bios_boot_delay */
13648 1, /* 10 scsi_reset_delay */
13649 1, /* bios_id_lun */
13650 1, /* 11 termination_se */
13651 1, /* termination_lvd */
13652 0, /* 12 bios_ctrl */
13653 0, /* 13 sdtr_speed2 */
13654 0, /* 14 sdtr_speed3 */
13655 1, /* 15 max_host_qng */
13656 1, /* max_dvc_qng */
13657 0, /* 16 dvc_cntl */
13658 0, /* 17 sdtr_speed4 */
13659 0, /* 18 serial_number_word1 */
13660 0, /* 19 serial_number_word2 */
13661 0, /* 20 serial_number_word3 */
13662 0, /* 21 check_sum */
13663 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13664 , /* 22-29 oem_name[16] */
13665 0, /* 30 dvc_err_code */
13666 0, /* 31 adv_err_code */
13667 0, /* 32 adv_err_addr */
13668 0, /* 33 saved_dvc_err_code */
13669 0, /* 34 saved_adv_err_code */
13670 0, /* 35 saved_adv_err_addr */
13671 0, /* 36 reserved */
13672 0, /* 37 reserved */
13673 0, /* 38 reserved */
13674 0, /* 39 reserved */
13675 0, /* 40 reserved */
13676 0, /* 41 reserved */
13677 0, /* 42 reserved */
13678 0, /* 43 reserved */
13679 0, /* 44 reserved */
13680 0, /* 45 reserved */
13681 0, /* 46 reserved */
13682 0, /* 47 reserved */
13683 0, /* 48 reserved */
13684 0, /* 49 reserved */
13685 0, /* 50 reserved */
13686 0, /* 51 reserved */
13687 0, /* 52 reserved */
13688 0, /* 53 reserved */
13689 0, /* 54 reserved */
13690 0, /* 55 reserved */
13691 0, /* 56 cisptr_lsw */
13692 0, /* 57 cisprt_msw */
13693 0, /* 58 subsysvid */
13694 0, /* 59 subsysid */
13695 0, /* 60 reserved */
13696 0, /* 61 reserved */
13697 0, /* 62 reserved */
13698 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013699};
13700
13701/*
13702 * Initialize the ADV_DVC_VAR structure.
13703 *
13704 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13705 *
13706 * For a non-fatal error return a warning code. If there are no warnings
13707 * then 0 is returned.
13708 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013709static int __devinit AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013710{
Matthew Wilcox9649af32007-07-26 21:51:47 -060013711 unsigned short warn_code = 0;
13712 AdvPortAddr iop_base = asc_dvc->iop_base;
13713 struct pci_dev *pdev = to_pci_dev(asc_dvc->cfg->dev);
13714 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013715 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013716
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013717 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013718
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013719 /*
13720 * Save the state of the PCI Configuration Command Register
13721 * "Parity Error Response Control" Bit. If the bit is clear (0),
13722 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
13723 * DMA parity errors.
13724 */
13725 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060013726 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
13727 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013728 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013729
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013730 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
13731 ADV_LIB_VERSION_MINOR;
13732 asc_dvc->cfg->chip_version =
13733 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013734
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013735 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
13736 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
13737 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013738
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013739 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
13740 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
13741 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013742
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013743 /*
13744 * Reset the chip to start and allow register writes.
13745 */
13746 if (AdvFindSignature(iop_base) == 0) {
13747 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
13748 return ADV_ERROR;
13749 } else {
13750 /*
13751 * The caller must set 'chip_type' to a valid setting.
13752 */
13753 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
13754 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
13755 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
13756 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13757 return ADV_ERROR;
13758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013759
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013760 /*
13761 * Reset Chip.
13762 */
13763 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13764 ADV_CTRL_REG_CMD_RESET);
13765 DvcSleepMilliSecond(100);
13766 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13767 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013768
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013769 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013770 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013771 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013772 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013773 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013774 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013775 }
13776 warn_code |= status;
13777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013778
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013779 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013780}
13781
13782/*
13783 * Initialize the ASC-3550.
13784 *
13785 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13786 *
13787 * For a non-fatal error return a warning code. If there are no warnings
13788 * then 0 is returned.
13789 *
13790 * Needed after initialization for error recovery.
13791 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013792static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013793{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013794 AdvPortAddr iop_base;
13795 ushort warn_code;
13796 ADV_DCNT sum;
13797 int begin_addr;
13798 int end_addr;
13799 ushort code_sum;
13800 int word;
13801 int j;
13802 int adv_asc3550_expanded_size;
13803 ADV_CARR_T *carrp;
13804 ADV_DCNT contig_len;
13805 ADV_SDCNT buf_size;
13806 ADV_PADDR carr_paddr;
13807 int i;
13808 ushort scsi_cfg1;
13809 uchar tid;
13810 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
13811 ushort wdtr_able = 0, sdtr_able, tagqng_able;
13812 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013813
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013814 /* If there is already an error, don't continue. */
13815 if (asc_dvc->err_code != 0) {
13816 return ADV_ERROR;
13817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013818
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013819 /*
13820 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
13821 */
13822 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
13823 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13824 return ADV_ERROR;
13825 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013826
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013827 warn_code = 0;
13828 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013829
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013830 /*
13831 * Save the RISC memory BIOS region before writing the microcode.
13832 * The BIOS may already be loaded and using its RISC LRAM region
13833 * so its region must be saved and restored.
13834 *
13835 * Note: This code makes the assumption, which is currently true,
13836 * that a chip reset does not clear RISC LRAM.
13837 */
13838 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13839 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13840 bios_mem[i]);
13841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013842
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013843 /*
13844 * Save current per TID negotiated values.
13845 */
13846 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
13847 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013848
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013849 bios_version =
13850 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
13851 major = (bios_version >> 12) & 0xF;
13852 minor = (bios_version >> 8) & 0xF;
13853 if (major < 3 || (major == 3 && minor == 1)) {
13854 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
13855 AdvReadWordLram(iop_base, 0x120, wdtr_able);
13856 } else {
13857 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13858 }
13859 }
13860 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13861 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13862 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13863 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13864 max_cmd[tid]);
13865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013866
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013867 /*
13868 * Load the Microcode
13869 *
13870 * Write the microcode image to RISC memory starting at address 0.
13871 */
13872 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
13873 /* Assume the following compressed format of the microcode buffer:
13874 *
13875 * 254 word (508 byte) table indexed by byte code followed
13876 * by the following byte codes:
13877 *
13878 * 1-Byte Code:
13879 * 00: Emit word 0 in table.
13880 * 01: Emit word 1 in table.
13881 * .
13882 * FD: Emit word 253 in table.
13883 *
13884 * Multi-Byte Code:
13885 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
13886 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
13887 */
13888 word = 0;
13889 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
13890 if (_adv_asc3550_buf[i] == 0xff) {
13891 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
13892 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13893 _adv_asc3550_buf
13894 [i +
13895 3] << 8) |
13896 _adv_asc3550_buf
13897 [i + 2]));
13898 word++;
13899 }
13900 i += 3;
13901 } else if (_adv_asc3550_buf[i] == 0xfe) {
13902 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13903 _adv_asc3550_buf[i +
13904 2]
13905 << 8) |
13906 _adv_asc3550_buf[i +
13907 1]));
13908 i += 2;
13909 word++;
13910 } else {
13911 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13912 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
13913 word++;
13914 }
13915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013916
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013917 /*
13918 * Set 'word' for later use to clear the rest of memory and save
13919 * the expanded mcode size.
13920 */
13921 word *= 2;
13922 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013923
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013924 /*
13925 * Clear the rest of ASC-3550 Internal RAM (8KB).
13926 */
13927 for (; word < ADV_3550_MEMSIZE; word += 2) {
13928 AdvWriteWordAutoIncLram(iop_base, 0);
13929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013930
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013931 /*
13932 * Verify the microcode checksum.
13933 */
13934 sum = 0;
13935 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013936
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013937 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
13938 sum += AdvReadWordAutoIncLram(iop_base);
13939 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013940
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013941 if (sum != _adv_asc3550_chksum) {
13942 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
13943 return ADV_ERROR;
13944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013945
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013946 /*
13947 * Restore the RISC memory BIOS region.
13948 */
13949 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13950 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13951 bios_mem[i]);
13952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013953
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013954 /*
13955 * Calculate and write the microcode code checksum to the microcode
13956 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
13957 */
13958 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
13959 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
13960 code_sum = 0;
13961 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
13962 for (word = begin_addr; word < end_addr; word += 2) {
13963 code_sum += AdvReadWordAutoIncLram(iop_base);
13964 }
13965 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013966
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013967 /*
13968 * Read and save microcode version and date.
13969 */
13970 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
13971 asc_dvc->cfg->mcode_date);
13972 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
13973 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013974
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013975 /*
13976 * Set the chip type to indicate the ASC3550.
13977 */
13978 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013979
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013980 /*
13981 * If the PCI Configuration Command Register "Parity Error Response
13982 * Control" Bit was clear (0), then set the microcode variable
13983 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
13984 * to ignore DMA parity errors.
13985 */
13986 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
13987 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13988 word |= CONTROL_FLAG_IGNORE_PERR;
13989 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
13990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013991
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013992 /*
13993 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
13994 * threshold of 128 bytes. This register is only accessible to the host.
13995 */
13996 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
13997 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013998
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013999 /*
14000 * Microcode operating variables for WDTR, SDTR, and command tag
14001 * queuing will be set in AdvInquiryHandling() based on what a
14002 * device reports it is capable of in Inquiry byte 7.
14003 *
14004 * If SCSI Bus Resets have been disabled, then directly set
14005 * SDTR and WDTR from the EEPROM configuration. This will allow
14006 * the BIOS and warm boot to work without a SCSI bus hang on
14007 * the Inquiry caused by host and target mismatched DTR values.
14008 * Without the SCSI Bus Reset, before an Inquiry a device can't
14009 * be assumed to be in Asynchronous, Narrow mode.
14010 */
14011 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14012 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14013 asc_dvc->wdtr_able);
14014 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14015 asc_dvc->sdtr_able);
14016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014017
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014018 /*
14019 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
14020 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
14021 * bitmask. These values determine the maximum SDTR speed negotiated
14022 * with a device.
14023 *
14024 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14025 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14026 * without determining here whether the device supports SDTR.
14027 *
14028 * 4-bit speed SDTR speed name
14029 * =========== ===============
14030 * 0000b (0x0) SDTR disabled
14031 * 0001b (0x1) 5 Mhz
14032 * 0010b (0x2) 10 Mhz
14033 * 0011b (0x3) 20 Mhz (Ultra)
14034 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
14035 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
14036 * 0110b (0x6) Undefined
14037 * .
14038 * 1111b (0xF) Undefined
14039 */
14040 word = 0;
14041 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14042 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
14043 /* Set Ultra speed for TID 'tid'. */
14044 word |= (0x3 << (4 * (tid % 4)));
14045 } else {
14046 /* Set Fast speed for TID 'tid'. */
14047 word |= (0x2 << (4 * (tid % 4)));
14048 }
14049 if (tid == 3) { /* Check if done with sdtr_speed1. */
14050 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
14051 word = 0;
14052 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
14053 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
14054 word = 0;
14055 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
14056 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
14057 word = 0;
14058 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
14059 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
14060 /* End of loop. */
14061 }
14062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014063
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014064 /*
14065 * Set microcode operating variable for the disconnect per TID bitmask.
14066 */
14067 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14068 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014069
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014070 /*
14071 * Set SCSI_CFG0 Microcode Default Value.
14072 *
14073 * The microcode will set the SCSI_CFG0 register using this value
14074 * after it is started below.
14075 */
14076 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14077 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14078 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014079
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014080 /*
14081 * Determine SCSI_CFG1 Microcode Default Value.
14082 *
14083 * The microcode will set the SCSI_CFG1 register using this value
14084 * after it is started below.
14085 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014086
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014087 /* Read current SCSI_CFG1 Register value. */
14088 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014089
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014090 /*
14091 * If all three connectors are in use, return an error.
14092 */
14093 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
14094 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
14095 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
14096 return ADV_ERROR;
14097 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014098
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014099 /*
14100 * If the internal narrow cable is reversed all of the SCSI_CTRL
14101 * register signals will be set. Check for and return an error if
14102 * this condition is found.
14103 */
14104 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14105 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14106 return ADV_ERROR;
14107 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014108
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014109 /*
14110 * If this is a differential board and a single-ended device
14111 * is attached to one of the connectors, return an error.
14112 */
14113 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
14114 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
14115 return ADV_ERROR;
14116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014117
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014118 /*
14119 * If automatic termination control is enabled, then set the
14120 * termination value based on a table listed in a_condor.h.
14121 *
14122 * If manual termination was specified with an EEPROM setting
14123 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
14124 * is ready to be 'ored' into SCSI_CFG1.
14125 */
14126 if (asc_dvc->cfg->termination == 0) {
14127 /*
14128 * The software always controls termination by setting TERM_CTL_SEL.
14129 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
14130 */
14131 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014132
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014133 switch (scsi_cfg1 & CABLE_DETECT) {
14134 /* TERM_CTL_H: on, TERM_CTL_L: on */
14135 case 0x3:
14136 case 0x7:
14137 case 0xB:
14138 case 0xD:
14139 case 0xE:
14140 case 0xF:
14141 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
14142 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014143
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014144 /* TERM_CTL_H: on, TERM_CTL_L: off */
14145 case 0x1:
14146 case 0x5:
14147 case 0x9:
14148 case 0xA:
14149 case 0xC:
14150 asc_dvc->cfg->termination |= TERM_CTL_H;
14151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014152
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014153 /* TERM_CTL_H: off, TERM_CTL_L: off */
14154 case 0x2:
14155 case 0x6:
14156 break;
14157 }
14158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014159
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014160 /*
14161 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
14162 */
14163 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014164
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014165 /*
14166 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
14167 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
14168 * referenced, because the hardware internally inverts
14169 * the Termination High and Low bits if TERM_POL is set.
14170 */
14171 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014172
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014173 /*
14174 * Set SCSI_CFG1 Microcode Default Value
14175 *
14176 * Set filter value and possibly modified termination control
14177 * bits in the Microcode SCSI_CFG1 Register Value.
14178 *
14179 * The microcode will set the SCSI_CFG1 register using this value
14180 * after it is started below.
14181 */
14182 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14183 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014184
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014185 /*
14186 * Set MEM_CFG Microcode Default Value
14187 *
14188 * The microcode will set the MEM_CFG register using this value
14189 * after it is started below.
14190 *
14191 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14192 * are defined.
14193 *
14194 * ASC-3550 has 8KB internal memory.
14195 */
14196 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14197 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014198
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014199 /*
14200 * Set SEL_MASK Microcode Default Value
14201 *
14202 * The microcode will set the SEL_MASK register using this value
14203 * after it is started below.
14204 */
14205 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14206 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014207
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014208 /*
14209 * Build carrier freelist.
14210 *
14211 * Driver must have already allocated memory and set 'carrier_buf'.
14212 */
14213 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014214
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014215 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14216 asc_dvc->carr_freelist = NULL;
14217 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14218 buf_size = ADV_CARRIER_BUFSIZE;
14219 } else {
14220 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014222
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014223 do {
14224 /*
14225 * Get physical address of the carrier 'carrp'.
14226 */
14227 contig_len = sizeof(ADV_CARR_T);
14228 carr_paddr =
14229 cpu_to_le32(DvcGetPhyAddr
14230 (asc_dvc, NULL, (uchar *)carrp,
14231 (ADV_SDCNT *)&contig_len,
14232 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014233
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014234 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014235
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014236 /*
14237 * If the current carrier is not physically contiguous, then
14238 * maybe there was a page crossing. Try the next carrier aligned
14239 * start address.
14240 */
14241 if (contig_len < sizeof(ADV_CARR_T)) {
14242 carrp++;
14243 continue;
14244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014245
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014246 carrp->carr_pa = carr_paddr;
14247 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014248
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014249 /*
14250 * Insert the carrier at the beginning of the freelist.
14251 */
14252 carrp->next_vpa =
14253 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14254 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014255
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014256 carrp++;
14257 }
14258 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014259
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014260 /*
14261 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14262 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014263
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014264 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14265 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14266 return ADV_ERROR;
14267 }
14268 asc_dvc->carr_freelist = (ADV_CARR_T *)
14269 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014270
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014271 /*
14272 * The first command issued will be placed in the stopper carrier.
14273 */
14274 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014275
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014276 /*
14277 * Set RISC ICQ physical address start value.
14278 */
14279 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014280
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014281 /*
14282 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14283 */
14284 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14285 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14286 return ADV_ERROR;
14287 }
14288 asc_dvc->carr_freelist = (ADV_CARR_T *)
14289 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014290
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014291 /*
14292 * The first command completed by the RISC will be placed in
14293 * the stopper.
14294 *
14295 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14296 * completed the RISC will set the ASC_RQ_STOPPER bit.
14297 */
14298 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014299
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014300 /*
14301 * Set RISC IRQ physical address start value.
14302 */
14303 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14304 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014306 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14307 (ADV_INTR_ENABLE_HOST_INTR |
14308 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014309
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014310 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14311 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014312
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014313 /* finally, finally, gentlemen, start your engine */
14314 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014315
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014316 /*
14317 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14318 * Resets should be performed. The RISC has to be running
14319 * to issue a SCSI Bus Reset.
14320 */
14321 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14322 /*
14323 * If the BIOS Signature is present in memory, restore the
14324 * BIOS Handshake Configuration Table and do not perform
14325 * a SCSI Bus Reset.
14326 */
14327 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14328 0x55AA) {
14329 /*
14330 * Restore per TID negotiated values.
14331 */
14332 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14333 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14334 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14335 tagqng_able);
14336 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14337 AdvWriteByteLram(iop_base,
14338 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14339 max_cmd[tid]);
14340 }
14341 } else {
14342 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14343 warn_code = ASC_WARN_BUSRESET_ERROR;
14344 }
14345 }
14346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014347
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014348 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014349}
14350
14351/*
14352 * Initialize the ASC-38C0800.
14353 *
14354 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14355 *
14356 * For a non-fatal error return a warning code. If there are no warnings
14357 * then 0 is returned.
14358 *
14359 * Needed after initialization for error recovery.
14360 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014361static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014362{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014363 AdvPortAddr iop_base;
14364 ushort warn_code;
14365 ADV_DCNT sum;
14366 int begin_addr;
14367 int end_addr;
14368 ushort code_sum;
14369 int word;
14370 int j;
14371 int adv_asc38C0800_expanded_size;
14372 ADV_CARR_T *carrp;
14373 ADV_DCNT contig_len;
14374 ADV_SDCNT buf_size;
14375 ADV_PADDR carr_paddr;
14376 int i;
14377 ushort scsi_cfg1;
14378 uchar byte;
14379 uchar tid;
14380 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14381 ushort wdtr_able, sdtr_able, tagqng_able;
14382 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014383
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014384 /* If there is already an error, don't continue. */
14385 if (asc_dvc->err_code != 0) {
14386 return ADV_ERROR;
14387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014388
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014389 /*
14390 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14391 */
14392 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14393 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14394 return ADV_ERROR;
14395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014396
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014397 warn_code = 0;
14398 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014399
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014400 /*
14401 * Save the RISC memory BIOS region before writing the microcode.
14402 * The BIOS may already be loaded and using its RISC LRAM region
14403 * so its region must be saved and restored.
14404 *
14405 * Note: This code makes the assumption, which is currently true,
14406 * that a chip reset does not clear RISC LRAM.
14407 */
14408 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14409 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14410 bios_mem[i]);
14411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014412
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014413 /*
14414 * Save current per TID negotiated values.
14415 */
14416 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14417 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14418 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14419 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14420 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14421 max_cmd[tid]);
14422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014423
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014424 /*
14425 * RAM BIST (RAM Built-In Self Test)
14426 *
14427 * Address : I/O base + offset 0x38h register (byte).
14428 * Function: Bit 7-6(RW) : RAM mode
14429 * Normal Mode : 0x00
14430 * Pre-test Mode : 0x40
14431 * RAM Test Mode : 0x80
14432 * Bit 5 : unused
14433 * Bit 4(RO) : Done bit
14434 * Bit 3-0(RO) : Status
14435 * Host Error : 0x08
14436 * Int_RAM Error : 0x04
14437 * RISC Error : 0x02
14438 * SCSI Error : 0x01
14439 * No Error : 0x00
14440 *
14441 * Note: RAM BIST code should be put right here, before loading the
14442 * microcode and after saving the RISC memory BIOS region.
14443 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014444
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014445 /*
14446 * LRAM Pre-test
14447 *
14448 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14449 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14450 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14451 * to NORMAL_MODE, return an error too.
14452 */
14453 for (i = 0; i < 2; i++) {
14454 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14455 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14456 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14457 if ((byte & RAM_TEST_DONE) == 0
14458 || (byte & 0x0F) != PRE_TEST_VALUE) {
14459 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14460 return ADV_ERROR;
14461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014462
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014463 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14464 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14465 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14466 != NORMAL_VALUE) {
14467 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14468 return ADV_ERROR;
14469 }
14470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014471
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014472 /*
14473 * LRAM Test - It takes about 1.5 ms to run through the test.
14474 *
14475 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14476 * If Done bit not set or Status not 0, save register byte, set the
14477 * err_code, and return an error.
14478 */
14479 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14480 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014481
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014482 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14483 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14484 /* Get here if Done bit not set or Status not 0. */
14485 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14486 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14487 return ADV_ERROR;
14488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014489
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014490 /* We need to reset back to normal mode after LRAM test passes. */
14491 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014492
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014493 /*
14494 * Load the Microcode
14495 *
14496 * Write the microcode image to RISC memory starting at address 0.
14497 *
14498 */
14499 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014500
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014501 /* Assume the following compressed format of the microcode buffer:
14502 *
14503 * 254 word (508 byte) table indexed by byte code followed
14504 * by the following byte codes:
14505 *
14506 * 1-Byte Code:
14507 * 00: Emit word 0 in table.
14508 * 01: Emit word 1 in table.
14509 * .
14510 * FD: Emit word 253 in table.
14511 *
14512 * Multi-Byte Code:
14513 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14514 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14515 */
14516 word = 0;
14517 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
14518 if (_adv_asc38C0800_buf[i] == 0xff) {
14519 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
14520 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14521 _adv_asc38C0800_buf
14522 [i +
14523 3] << 8) |
14524 _adv_asc38C0800_buf
14525 [i + 2]));
14526 word++;
14527 }
14528 i += 3;
14529 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
14530 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14531 _adv_asc38C0800_buf
14532 [i +
14533 2] << 8) |
14534 _adv_asc38C0800_buf[i
14535 +
14536 1]));
14537 i += 2;
14538 word++;
14539 } else {
14540 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14541 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
14542 word++;
14543 }
14544 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014545
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014546 /*
14547 * Set 'word' for later use to clear the rest of memory and save
14548 * the expanded mcode size.
14549 */
14550 word *= 2;
14551 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014552
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014553 /*
14554 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
14555 */
14556 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
14557 AdvWriteWordAutoIncLram(iop_base, 0);
14558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014559
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014560 /*
14561 * Verify the microcode checksum.
14562 */
14563 sum = 0;
14564 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014565
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014566 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
14567 sum += AdvReadWordAutoIncLram(iop_base);
14568 }
14569 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014570
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014571 ASC_DBG2(1,
14572 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
14573 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014574
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014575 if (sum != _adv_asc38C0800_chksum) {
14576 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14577 return ADV_ERROR;
14578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014579
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014580 /*
14581 * Restore the RISC memory BIOS region.
14582 */
14583 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14584 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14585 bios_mem[i]);
14586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014587
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014588 /*
14589 * Calculate and write the microcode code checksum to the microcode
14590 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14591 */
14592 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14593 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14594 code_sum = 0;
14595 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14596 for (word = begin_addr; word < end_addr; word += 2) {
14597 code_sum += AdvReadWordAutoIncLram(iop_base);
14598 }
14599 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014600
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014601 /*
14602 * Read microcode version and date.
14603 */
14604 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14605 asc_dvc->cfg->mcode_date);
14606 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14607 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014608
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014609 /*
14610 * Set the chip type to indicate the ASC38C0800.
14611 */
14612 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014613
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014614 /*
14615 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
14616 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
14617 * cable detection and then we are able to read C_DET[3:0].
14618 *
14619 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
14620 * Microcode Default Value' section below.
14621 */
14622 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
14623 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
14624 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014625
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014626 /*
14627 * If the PCI Configuration Command Register "Parity Error Response
14628 * Control" Bit was clear (0), then set the microcode variable
14629 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14630 * to ignore DMA parity errors.
14631 */
14632 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14633 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14634 word |= CONTROL_FLAG_IGNORE_PERR;
14635 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14636 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014637
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014638 /*
14639 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
14640 * bits for the default FIFO threshold.
14641 *
14642 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
14643 *
14644 * For DMA Errata #4 set the BC_THRESH_ENB bit.
14645 */
14646 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14647 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
14648 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014649
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014650 /*
14651 * Microcode operating variables for WDTR, SDTR, and command tag
14652 * queuing will be set in AdvInquiryHandling() based on what a
14653 * device reports it is capable of in Inquiry byte 7.
14654 *
14655 * If SCSI Bus Resets have been disabled, then directly set
14656 * SDTR and WDTR from the EEPROM configuration. This will allow
14657 * the BIOS and warm boot to work without a SCSI bus hang on
14658 * the Inquiry caused by host and target mismatched DTR values.
14659 * Without the SCSI Bus Reset, before an Inquiry a device can't
14660 * be assumed to be in Asynchronous, Narrow mode.
14661 */
14662 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14663 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14664 asc_dvc->wdtr_able);
14665 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14666 asc_dvc->sdtr_able);
14667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014668
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014669 /*
14670 * Set microcode operating variables for DISC and SDTR_SPEED1,
14671 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
14672 * configuration values.
14673 *
14674 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14675 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14676 * without determining here whether the device supports SDTR.
14677 */
14678 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14679 asc_dvc->cfg->disc_enable);
14680 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
14681 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
14682 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
14683 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014684
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014685 /*
14686 * Set SCSI_CFG0 Microcode Default Value.
14687 *
14688 * The microcode will set the SCSI_CFG0 register using this value
14689 * after it is started below.
14690 */
14691 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14692 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14693 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014694
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014695 /*
14696 * Determine SCSI_CFG1 Microcode Default Value.
14697 *
14698 * The microcode will set the SCSI_CFG1 register using this value
14699 * after it is started below.
14700 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014701
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014702 /* Read current SCSI_CFG1 Register value. */
14703 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014704
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014705 /*
14706 * If the internal narrow cable is reversed all of the SCSI_CTRL
14707 * register signals will be set. Check for and return an error if
14708 * this condition is found.
14709 */
14710 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14711 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14712 return ADV_ERROR;
14713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014714
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014715 /*
14716 * All kind of combinations of devices attached to one of four connectors
14717 * are acceptable except HVD device attached. For example, LVD device can
14718 * be attached to SE connector while SE device attached to LVD connector.
14719 * If LVD device attached to SE connector, it only runs up to Ultra speed.
14720 *
14721 * If an HVD device is attached to one of LVD connectors, return an error.
14722 * However, there is no way to detect HVD device attached to SE connectors.
14723 */
14724 if (scsi_cfg1 & HVD) {
14725 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
14726 return ADV_ERROR;
14727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014728
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014729 /*
14730 * If either SE or LVD automatic termination control is enabled, then
14731 * set the termination value based on a table listed in a_condor.h.
14732 *
14733 * If manual termination was specified with an EEPROM setting then
14734 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
14735 * be 'ored' into SCSI_CFG1.
14736 */
14737 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
14738 /* SE automatic termination control is enabled. */
14739 switch (scsi_cfg1 & C_DET_SE) {
14740 /* TERM_SE_HI: on, TERM_SE_LO: on */
14741 case 0x1:
14742 case 0x2:
14743 case 0x3:
14744 asc_dvc->cfg->termination |= TERM_SE;
14745 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014746
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014747 /* TERM_SE_HI: on, TERM_SE_LO: off */
14748 case 0x0:
14749 asc_dvc->cfg->termination |= TERM_SE_HI;
14750 break;
14751 }
14752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014753
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014754 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
14755 /* LVD automatic termination control is enabled. */
14756 switch (scsi_cfg1 & C_DET_LVD) {
14757 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
14758 case 0x4:
14759 case 0x8:
14760 case 0xC:
14761 asc_dvc->cfg->termination |= TERM_LVD;
14762 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014763
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014764 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
14765 case 0x0:
14766 break;
14767 }
14768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014769
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014770 /*
14771 * Clear any set TERM_SE and TERM_LVD bits.
14772 */
14773 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014774
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014775 /*
14776 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
14777 */
14778 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014779
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014780 /*
14781 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
14782 * and set possibly modified termination control bits in the Microcode
14783 * SCSI_CFG1 Register Value.
14784 */
14785 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014786
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014787 /*
14788 * Set SCSI_CFG1 Microcode Default Value
14789 *
14790 * Set possibly modified termination control and reset DIS_TERM_DRV
14791 * bits in the Microcode SCSI_CFG1 Register Value.
14792 *
14793 * The microcode will set the SCSI_CFG1 register using this value
14794 * after it is started below.
14795 */
14796 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014797
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014798 /*
14799 * Set MEM_CFG Microcode Default Value
14800 *
14801 * The microcode will set the MEM_CFG register using this value
14802 * after it is started below.
14803 *
14804 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14805 * are defined.
14806 *
14807 * ASC-38C0800 has 16KB internal memory.
14808 */
14809 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14810 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014811
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014812 /*
14813 * Set SEL_MASK Microcode Default Value
14814 *
14815 * The microcode will set the SEL_MASK register using this value
14816 * after it is started below.
14817 */
14818 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14819 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014820
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014821 /*
14822 * Build the carrier freelist.
14823 *
14824 * Driver must have already allocated memory and set 'carrier_buf'.
14825 */
14826 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014827
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014828 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14829 asc_dvc->carr_freelist = NULL;
14830 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14831 buf_size = ADV_CARRIER_BUFSIZE;
14832 } else {
14833 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14834 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014835
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014836 do {
14837 /*
14838 * Get physical address for the carrier 'carrp'.
14839 */
14840 contig_len = sizeof(ADV_CARR_T);
14841 carr_paddr =
14842 cpu_to_le32(DvcGetPhyAddr
14843 (asc_dvc, NULL, (uchar *)carrp,
14844 (ADV_SDCNT *)&contig_len,
14845 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014846
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014847 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014848
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014849 /*
14850 * If the current carrier is not physically contiguous, then
14851 * maybe there was a page crossing. Try the next carrier aligned
14852 * start address.
14853 */
14854 if (contig_len < sizeof(ADV_CARR_T)) {
14855 carrp++;
14856 continue;
14857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014858
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014859 carrp->carr_pa = carr_paddr;
14860 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014861
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014862 /*
14863 * Insert the carrier at the beginning of the freelist.
14864 */
14865 carrp->next_vpa =
14866 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14867 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014868
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014869 carrp++;
14870 }
14871 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014872
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014873 /*
14874 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14875 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014876
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014877 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14878 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14879 return ADV_ERROR;
14880 }
14881 asc_dvc->carr_freelist = (ADV_CARR_T *)
14882 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014883
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014884 /*
14885 * The first command issued will be placed in the stopper carrier.
14886 */
14887 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014888
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014889 /*
14890 * Set RISC ICQ physical address start value.
14891 * carr_pa is LE, must be native before write
14892 */
14893 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014894
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014895 /*
14896 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14897 */
14898 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14899 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14900 return ADV_ERROR;
14901 }
14902 asc_dvc->carr_freelist = (ADV_CARR_T *)
14903 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014904
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014905 /*
14906 * The first command completed by the RISC will be placed in
14907 * the stopper.
14908 *
14909 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14910 * completed the RISC will set the ASC_RQ_STOPPER bit.
14911 */
14912 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014913
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014914 /*
14915 * Set RISC IRQ physical address start value.
14916 *
14917 * carr_pa is LE, must be native before write *
14918 */
14919 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14920 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014921
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014922 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14923 (ADV_INTR_ENABLE_HOST_INTR |
14924 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014925
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014926 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14927 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014928
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014929 /* finally, finally, gentlemen, start your engine */
14930 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014931
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014932 /*
14933 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14934 * Resets should be performed. The RISC has to be running
14935 * to issue a SCSI Bus Reset.
14936 */
14937 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14938 /*
14939 * If the BIOS Signature is present in memory, restore the
14940 * BIOS Handshake Configuration Table and do not perform
14941 * a SCSI Bus Reset.
14942 */
14943 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14944 0x55AA) {
14945 /*
14946 * Restore per TID negotiated values.
14947 */
14948 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14949 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14950 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14951 tagqng_able);
14952 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14953 AdvWriteByteLram(iop_base,
14954 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14955 max_cmd[tid]);
14956 }
14957 } else {
14958 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14959 warn_code = ASC_WARN_BUSRESET_ERROR;
14960 }
14961 }
14962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014963
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014964 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014965}
14966
14967/*
14968 * Initialize the ASC-38C1600.
14969 *
14970 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
14971 *
14972 * For a non-fatal error return a warning code. If there are no warnings
14973 * then 0 is returned.
14974 *
14975 * Needed after initialization for error recovery.
14976 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014977static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014978{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014979 AdvPortAddr iop_base;
14980 ushort warn_code;
14981 ADV_DCNT sum;
14982 int begin_addr;
14983 int end_addr;
14984 ushort code_sum;
14985 long word;
14986 int j;
14987 int adv_asc38C1600_expanded_size;
14988 ADV_CARR_T *carrp;
14989 ADV_DCNT contig_len;
14990 ADV_SDCNT buf_size;
14991 ADV_PADDR carr_paddr;
14992 int i;
14993 ushort scsi_cfg1;
14994 uchar byte;
14995 uchar tid;
14996 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14997 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
14998 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014999
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015000 /* If there is already an error, don't continue. */
15001 if (asc_dvc->err_code != 0) {
15002 return ADV_ERROR;
15003 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015004
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015005 /*
15006 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
15007 */
15008 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
15009 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
15010 return ADV_ERROR;
15011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015012
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015013 warn_code = 0;
15014 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015015
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015016 /*
15017 * Save the RISC memory BIOS region before writing the microcode.
15018 * The BIOS may already be loaded and using its RISC LRAM region
15019 * so its region must be saved and restored.
15020 *
15021 * Note: This code makes the assumption, which is currently true,
15022 * that a chip reset does not clear RISC LRAM.
15023 */
15024 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15025 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15026 bios_mem[i]);
15027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015028
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015029 /*
15030 * Save current per TID negotiated values.
15031 */
15032 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15033 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15034 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15035 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
15036 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15037 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
15038 max_cmd[tid]);
15039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015040
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015041 /*
15042 * RAM BIST (Built-In Self Test)
15043 *
15044 * Address : I/O base + offset 0x38h register (byte).
15045 * Function: Bit 7-6(RW) : RAM mode
15046 * Normal Mode : 0x00
15047 * Pre-test Mode : 0x40
15048 * RAM Test Mode : 0x80
15049 * Bit 5 : unused
15050 * Bit 4(RO) : Done bit
15051 * Bit 3-0(RO) : Status
15052 * Host Error : 0x08
15053 * Int_RAM Error : 0x04
15054 * RISC Error : 0x02
15055 * SCSI Error : 0x01
15056 * No Error : 0x00
15057 *
15058 * Note: RAM BIST code should be put right here, before loading the
15059 * microcode and after saving the RISC memory BIOS region.
15060 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015061
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015062 /*
15063 * LRAM Pre-test
15064 *
15065 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
15066 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
15067 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
15068 * to NORMAL_MODE, return an error too.
15069 */
15070 for (i = 0; i < 2; i++) {
15071 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
15072 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15073 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15074 if ((byte & RAM_TEST_DONE) == 0
15075 || (byte & 0x0F) != PRE_TEST_VALUE) {
15076 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15077 return ADV_ERROR;
15078 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015079
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015080 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
15081 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15082 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
15083 != NORMAL_VALUE) {
15084 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15085 return ADV_ERROR;
15086 }
15087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015089 /*
15090 * LRAM Test - It takes about 1.5 ms to run through the test.
15091 *
15092 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
15093 * If Done bit not set or Status not 0, save register byte, set the
15094 * err_code, and return an error.
15095 */
15096 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
15097 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015098
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015099 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15100 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
15101 /* Get here if Done bit not set or Status not 0. */
15102 asc_dvc->bist_err_code = byte; /* for BIOS display message */
15103 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
15104 return ADV_ERROR;
15105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015106
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015107 /* We need to reset back to normal mode after LRAM test passes. */
15108 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015109
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015110 /*
15111 * Load the Microcode
15112 *
15113 * Write the microcode image to RISC memory starting at address 0.
15114 *
15115 */
15116 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015117
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015118 /*
15119 * Assume the following compressed format of the microcode buffer:
15120 *
15121 * 254 word (508 byte) table indexed by byte code followed
15122 * by the following byte codes:
15123 *
15124 * 1-Byte Code:
15125 * 00: Emit word 0 in table.
15126 * 01: Emit word 1 in table.
15127 * .
15128 * FD: Emit word 253 in table.
15129 *
15130 * Multi-Byte Code:
15131 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15132 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15133 */
15134 word = 0;
15135 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
15136 if (_adv_asc38C1600_buf[i] == 0xff) {
15137 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
15138 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15139 _adv_asc38C1600_buf
15140 [i +
15141 3] << 8) |
15142 _adv_asc38C1600_buf
15143 [i + 2]));
15144 word++;
15145 }
15146 i += 3;
15147 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
15148 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15149 _adv_asc38C1600_buf
15150 [i +
15151 2] << 8) |
15152 _adv_asc38C1600_buf[i
15153 +
15154 1]));
15155 i += 2;
15156 word++;
15157 } else {
15158 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15159 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
15160 word++;
15161 }
15162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015163
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015164 /*
15165 * Set 'word' for later use to clear the rest of memory and save
15166 * the expanded mcode size.
15167 */
15168 word *= 2;
15169 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015170
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015171 /*
15172 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15173 */
15174 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15175 AdvWriteWordAutoIncLram(iop_base, 0);
15176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015177
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015178 /*
15179 * Verify the microcode checksum.
15180 */
15181 sum = 0;
15182 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015183
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015184 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15185 sum += AdvReadWordAutoIncLram(iop_base);
15186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015187
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015188 if (sum != _adv_asc38C1600_chksum) {
15189 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15190 return ADV_ERROR;
15191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015192
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015193 /*
15194 * Restore the RISC memory BIOS region.
15195 */
15196 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15197 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15198 bios_mem[i]);
15199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015200
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015201 /*
15202 * Calculate and write the microcode code checksum to the microcode
15203 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15204 */
15205 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15206 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15207 code_sum = 0;
15208 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15209 for (word = begin_addr; word < end_addr; word += 2) {
15210 code_sum += AdvReadWordAutoIncLram(iop_base);
15211 }
15212 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015213
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015214 /*
15215 * Read microcode version and date.
15216 */
15217 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15218 asc_dvc->cfg->mcode_date);
15219 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15220 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015221
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015222 /*
15223 * Set the chip type to indicate the ASC38C1600.
15224 */
15225 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015226
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015227 /*
15228 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15229 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15230 * cable detection and then we are able to read C_DET[3:0].
15231 *
15232 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15233 * Microcode Default Value' section below.
15234 */
15235 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15236 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15237 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015238
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015239 /*
15240 * If the PCI Configuration Command Register "Parity Error Response
15241 * Control" Bit was clear (0), then set the microcode variable
15242 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15243 * to ignore DMA parity errors.
15244 */
15245 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15246 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15247 word |= CONTROL_FLAG_IGNORE_PERR;
15248 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015250
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015251 /*
15252 * If the BIOS control flag AIPP (Asynchronous Information
15253 * Phase Protection) disable bit is not set, then set the firmware
15254 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15255 * AIPP checking and encoding.
15256 */
15257 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15258 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15259 word |= CONTROL_FLAG_ENABLE_AIPP;
15260 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015263 /*
15264 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15265 * and START_CTL_TH [3:2].
15266 */
15267 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15268 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015269
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015270 /*
15271 * Microcode operating variables for WDTR, SDTR, and command tag
15272 * queuing will be set in AdvInquiryHandling() based on what a
15273 * device reports it is capable of in Inquiry byte 7.
15274 *
15275 * If SCSI Bus Resets have been disabled, then directly set
15276 * SDTR and WDTR from the EEPROM configuration. This will allow
15277 * the BIOS and warm boot to work without a SCSI bus hang on
15278 * the Inquiry caused by host and target mismatched DTR values.
15279 * Without the SCSI Bus Reset, before an Inquiry a device can't
15280 * be assumed to be in Asynchronous, Narrow mode.
15281 */
15282 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15283 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15284 asc_dvc->wdtr_able);
15285 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15286 asc_dvc->sdtr_able);
15287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015288
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015289 /*
15290 * Set microcode operating variables for DISC and SDTR_SPEED1,
15291 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15292 * configuration values.
15293 *
15294 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15295 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15296 * without determining here whether the device supports SDTR.
15297 */
15298 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15299 asc_dvc->cfg->disc_enable);
15300 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15301 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15302 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15303 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015304
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015305 /*
15306 * Set SCSI_CFG0 Microcode Default Value.
15307 *
15308 * The microcode will set the SCSI_CFG0 register using this value
15309 * after it is started below.
15310 */
15311 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15312 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15313 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015314
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015315 /*
15316 * Calculate SCSI_CFG1 Microcode Default Value.
15317 *
15318 * The microcode will set the SCSI_CFG1 register using this value
15319 * after it is started below.
15320 *
15321 * Each ASC-38C1600 function has only two cable detect bits.
15322 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15323 */
15324 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015325
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015326 /*
15327 * If the cable is reversed all of the SCSI_CTRL register signals
15328 * will be set. Check for and return an error if this condition is
15329 * found.
15330 */
15331 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15332 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15333 return ADV_ERROR;
15334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015335
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015336 /*
15337 * Each ASC-38C1600 function has two connectors. Only an HVD device
15338 * can not be connected to either connector. An LVD device or SE device
15339 * may be connected to either connecor. If an SE device is connected,
15340 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15341 *
15342 * If an HVD device is attached, return an error.
15343 */
15344 if (scsi_cfg1 & HVD) {
15345 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15346 return ADV_ERROR;
15347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015348
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015349 /*
15350 * Each function in the ASC-38C1600 uses only the SE cable detect and
15351 * termination because there are two connectors for each function. Each
15352 * function may use either LVD or SE mode. Corresponding the SE automatic
15353 * termination control EEPROM bits are used for each function. Each
15354 * function has its own EEPROM. If SE automatic control is enabled for
15355 * the function, then set the termination value based on a table listed
15356 * in a_condor.h.
15357 *
15358 * If manual termination is specified in the EEPROM for the function,
15359 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15360 * ready to be 'ored' into SCSI_CFG1.
15361 */
15362 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15363 /* SE automatic termination control is enabled. */
15364 switch (scsi_cfg1 & C_DET_SE) {
15365 /* TERM_SE_HI: on, TERM_SE_LO: on */
15366 case 0x1:
15367 case 0x2:
15368 case 0x3:
15369 asc_dvc->cfg->termination |= TERM_SE;
15370 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015371
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015372 case 0x0:
15373 if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
15374 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15375 } else {
15376 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15377 asc_dvc->cfg->termination |= TERM_SE_HI;
15378 }
15379 break;
15380 }
15381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015383 /*
15384 * Clear any set TERM_SE bits.
15385 */
15386 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015387
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015388 /*
15389 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15390 */
15391 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015392
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015393 /*
15394 * Clear Big Endian and Terminator Polarity bits and set possibly
15395 * modified termination control bits in the Microcode SCSI_CFG1
15396 * Register Value.
15397 *
15398 * Big Endian bit is not used even on big endian machines.
15399 */
15400 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015401
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015402 /*
15403 * Set SCSI_CFG1 Microcode Default Value
15404 *
15405 * Set possibly modified termination control bits in the Microcode
15406 * SCSI_CFG1 Register Value.
15407 *
15408 * The microcode will set the SCSI_CFG1 register using this value
15409 * after it is started below.
15410 */
15411 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015412
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015413 /*
15414 * Set MEM_CFG Microcode Default Value
15415 *
15416 * The microcode will set the MEM_CFG register using this value
15417 * after it is started below.
15418 *
15419 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15420 * are defined.
15421 *
15422 * ASC-38C1600 has 32KB internal memory.
15423 *
15424 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15425 * out a special 16K Adv Library and Microcode version. After the issue
15426 * resolved, we should turn back to the 32K support. Both a_condor.h and
15427 * mcode.sas files also need to be updated.
15428 *
15429 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15430 * BIOS_EN | RAM_SZ_32KB);
15431 */
15432 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15433 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015434
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015435 /*
15436 * Set SEL_MASK Microcode Default Value
15437 *
15438 * The microcode will set the SEL_MASK register using this value
15439 * after it is started below.
15440 */
15441 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15442 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015443
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015444 /*
15445 * Build the carrier freelist.
15446 *
15447 * Driver must have already allocated memory and set 'carrier_buf'.
15448 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015449
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015450 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015451
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015452 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15453 asc_dvc->carr_freelist = NULL;
15454 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15455 buf_size = ADV_CARRIER_BUFSIZE;
15456 } else {
15457 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015459
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015460 do {
15461 /*
15462 * Get physical address for the carrier 'carrp'.
15463 */
15464 contig_len = sizeof(ADV_CARR_T);
15465 carr_paddr =
15466 cpu_to_le32(DvcGetPhyAddr
15467 (asc_dvc, NULL, (uchar *)carrp,
15468 (ADV_SDCNT *)&contig_len,
15469 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015470
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015471 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015472
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015473 /*
15474 * If the current carrier is not physically contiguous, then
15475 * maybe there was a page crossing. Try the next carrier aligned
15476 * start address.
15477 */
15478 if (contig_len < sizeof(ADV_CARR_T)) {
15479 carrp++;
15480 continue;
15481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015482
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015483 carrp->carr_pa = carr_paddr;
15484 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015485
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015486 /*
15487 * Insert the carrier at the beginning of the freelist.
15488 */
15489 carrp->next_vpa =
15490 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15491 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015492
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015493 carrp++;
15494 }
15495 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015496
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015497 /*
15498 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15499 */
15500 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15501 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15502 return ADV_ERROR;
15503 }
15504 asc_dvc->carr_freelist = (ADV_CARR_T *)
15505 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015506
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015507 /*
15508 * The first command issued will be placed in the stopper carrier.
15509 */
15510 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015511
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015512 /*
15513 * Set RISC ICQ physical address start value. Initialize the
15514 * COMMA register to the same value otherwise the RISC will
15515 * prematurely detect a command is available.
15516 */
15517 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
15518 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
15519 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015520
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015521 /*
15522 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15523 */
15524 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15525 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15526 return ADV_ERROR;
15527 }
15528 asc_dvc->carr_freelist = (ADV_CARR_T *)
15529 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015530
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015531 /*
15532 * The first command completed by the RISC will be placed in
15533 * the stopper.
15534 *
15535 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15536 * completed the RISC will set the ASC_RQ_STOPPER bit.
15537 */
15538 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015539
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015540 /*
15541 * Set RISC IRQ physical address start value.
15542 */
15543 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15544 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015545
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015546 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15547 (ADV_INTR_ENABLE_HOST_INTR |
15548 ADV_INTR_ENABLE_GLOBAL_INTR));
15549 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15550 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015551
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015552 /* finally, finally, gentlemen, start your engine */
15553 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015554
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015555 /*
15556 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15557 * Resets should be performed. The RISC has to be running
15558 * to issue a SCSI Bus Reset.
15559 */
15560 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15561 /*
15562 * If the BIOS Signature is present in memory, restore the
15563 * per TID microcode operating variables.
15564 */
15565 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15566 0x55AA) {
15567 /*
15568 * Restore per TID negotiated values.
15569 */
15570 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15571 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15572 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15573 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15574 tagqng_able);
15575 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15576 AdvWriteByteLram(iop_base,
15577 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15578 max_cmd[tid]);
15579 }
15580 } else {
15581 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15582 warn_code = ASC_WARN_BUSRESET_ERROR;
15583 }
15584 }
15585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015586
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015587 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015588}
15589
15590/*
15591 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15592 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15593 * all of this is done.
15594 *
15595 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15596 *
15597 * For a non-fatal error return a warning code. If there are no warnings
15598 * then 0 is returned.
15599 *
15600 * Note: Chip is stopped on entry.
15601 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015602static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015603{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015604 AdvPortAddr iop_base;
15605 ushort warn_code;
15606 ADVEEP_3550_CONFIG eep_config;
15607 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015608
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015609 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015610
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015611 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015612
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015613 /*
15614 * Read the board's EEPROM configuration.
15615 *
15616 * Set default values if a bad checksum is found.
15617 */
15618 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
15619 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015620
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015621 /*
15622 * Set EEPROM default values.
15623 */
15624 for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
15625 *((uchar *)&eep_config + i) =
15626 *((uchar *)&Default_3550_EEPROM_Config + i);
15627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015629 /*
15630 * Assume the 6 byte board serial number that was read
15631 * from EEPROM is correct even if the EEPROM checksum
15632 * failed.
15633 */
15634 eep_config.serial_number_word3 =
15635 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015636
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015637 eep_config.serial_number_word2 =
15638 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015639
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015640 eep_config.serial_number_word1 =
15641 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015643 AdvSet3550EEPConfig(iop_base, &eep_config);
15644 }
15645 /*
15646 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15647 * EEPROM configuration that was read.
15648 *
15649 * This is the mapping of EEPROM fields to Adv Library fields.
15650 */
15651 asc_dvc->wdtr_able = eep_config.wdtr_able;
15652 asc_dvc->sdtr_able = eep_config.sdtr_able;
15653 asc_dvc->ultra_able = eep_config.ultra_able;
15654 asc_dvc->tagqng_able = eep_config.tagqng_able;
15655 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15656 asc_dvc->max_host_qng = eep_config.max_host_qng;
15657 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15658 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15659 asc_dvc->start_motor = eep_config.start_motor;
15660 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15661 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15662 asc_dvc->no_scam = eep_config.scam_tolerant;
15663 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15664 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15665 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015666
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015667 /*
15668 * Set the host maximum queuing (max. 253, min. 16) and the per device
15669 * maximum queuing (max. 63, min. 4).
15670 */
15671 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15672 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15673 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15674 /* If the value is zero, assume it is uninitialized. */
15675 if (eep_config.max_host_qng == 0) {
15676 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15677 } else {
15678 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15679 }
15680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015681
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015682 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15683 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15684 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15685 /* If the value is zero, assume it is uninitialized. */
15686 if (eep_config.max_dvc_qng == 0) {
15687 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15688 } else {
15689 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15690 }
15691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015692
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015693 /*
15694 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15695 * set 'max_dvc_qng' to 'max_host_qng'.
15696 */
15697 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15698 eep_config.max_dvc_qng = eep_config.max_host_qng;
15699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015700
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015701 /*
15702 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15703 * values based on possibly adjusted EEPROM values.
15704 */
15705 asc_dvc->max_host_qng = eep_config.max_host_qng;
15706 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015707
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015708 /*
15709 * If the EEPROM 'termination' field is set to automatic (0), then set
15710 * the ADV_DVC_CFG 'termination' field to automatic also.
15711 *
15712 * If the termination is specified with a non-zero 'termination'
15713 * value check that a legal value is set and set the ADV_DVC_CFG
15714 * 'termination' field appropriately.
15715 */
15716 if (eep_config.termination == 0) {
15717 asc_dvc->cfg->termination = 0; /* auto termination */
15718 } else {
15719 /* Enable manual control with low off / high off. */
15720 if (eep_config.termination == 1) {
15721 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015722
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015723 /* Enable manual control with low off / high on. */
15724 } else if (eep_config.termination == 2) {
15725 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015726
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015727 /* Enable manual control with low on / high on. */
15728 } else if (eep_config.termination == 3) {
15729 asc_dvc->cfg->termination =
15730 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
15731 } else {
15732 /*
15733 * The EEPROM 'termination' field contains a bad value. Use
15734 * automatic termination instead.
15735 */
15736 asc_dvc->cfg->termination = 0;
15737 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15738 }
15739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015740
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015741 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015742}
15743
15744/*
15745 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15746 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15747 * all of this is done.
15748 *
15749 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15750 *
15751 * For a non-fatal error return a warning code. If there are no warnings
15752 * then 0 is returned.
15753 *
15754 * Note: Chip is stopped on entry.
15755 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015756static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015757{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015758 AdvPortAddr iop_base;
15759 ushort warn_code;
15760 ADVEEP_38C0800_CONFIG eep_config;
15761 int i;
15762 uchar tid, termination;
15763 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015764
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015765 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015766
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015767 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015768
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015769 /*
15770 * Read the board's EEPROM configuration.
15771 *
15772 * Set default values if a bad checksum is found.
15773 */
15774 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
15775 eep_config.check_sum) {
15776 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015777
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015778 /*
15779 * Set EEPROM default values.
15780 */
15781 for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
15782 *((uchar *)&eep_config + i) =
15783 *((uchar *)&Default_38C0800_EEPROM_Config + i);
15784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015785
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015786 /*
15787 * Assume the 6 byte board serial number that was read
15788 * from EEPROM is correct even if the EEPROM checksum
15789 * failed.
15790 */
15791 eep_config.serial_number_word3 =
15792 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015793
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015794 eep_config.serial_number_word2 =
15795 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015796
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015797 eep_config.serial_number_word1 =
15798 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015799
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015800 AdvSet38C0800EEPConfig(iop_base, &eep_config);
15801 }
15802 /*
15803 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
15804 * EEPROM configuration that was read.
15805 *
15806 * This is the mapping of EEPROM fields to Adv Library fields.
15807 */
15808 asc_dvc->wdtr_able = eep_config.wdtr_able;
15809 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15810 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15811 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15812 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15813 asc_dvc->tagqng_able = eep_config.tagqng_able;
15814 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15815 asc_dvc->max_host_qng = eep_config.max_host_qng;
15816 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15817 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15818 asc_dvc->start_motor = eep_config.start_motor;
15819 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15820 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15821 asc_dvc->no_scam = eep_config.scam_tolerant;
15822 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15823 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15824 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015825
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015826 /*
15827 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15828 * are set, then set an 'sdtr_able' bit for it.
15829 */
15830 asc_dvc->sdtr_able = 0;
15831 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15832 if (tid == 0) {
15833 sdtr_speed = asc_dvc->sdtr_speed1;
15834 } else if (tid == 4) {
15835 sdtr_speed = asc_dvc->sdtr_speed2;
15836 } else if (tid == 8) {
15837 sdtr_speed = asc_dvc->sdtr_speed3;
15838 } else if (tid == 12) {
15839 sdtr_speed = asc_dvc->sdtr_speed4;
15840 }
15841 if (sdtr_speed & ADV_MAX_TID) {
15842 asc_dvc->sdtr_able |= (1 << tid);
15843 }
15844 sdtr_speed >>= 4;
15845 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015846
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015847 /*
15848 * Set the host maximum queuing (max. 253, min. 16) and the per device
15849 * maximum queuing (max. 63, min. 4).
15850 */
15851 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15852 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15853 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15854 /* If the value is zero, assume it is uninitialized. */
15855 if (eep_config.max_host_qng == 0) {
15856 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15857 } else {
15858 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15859 }
15860 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015861
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015862 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15863 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15864 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15865 /* If the value is zero, assume it is uninitialized. */
15866 if (eep_config.max_dvc_qng == 0) {
15867 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15868 } else {
15869 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15870 }
15871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015872
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015873 /*
15874 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15875 * set 'max_dvc_qng' to 'max_host_qng'.
15876 */
15877 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15878 eep_config.max_dvc_qng = eep_config.max_host_qng;
15879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015880
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015881 /*
15882 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15883 * values based on possibly adjusted EEPROM values.
15884 */
15885 asc_dvc->max_host_qng = eep_config.max_host_qng;
15886 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015887
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015888 /*
15889 * If the EEPROM 'termination' field is set to automatic (0), then set
15890 * the ADV_DVC_CFG 'termination' field to automatic also.
15891 *
15892 * If the termination is specified with a non-zero 'termination'
15893 * value check that a legal value is set and set the ADV_DVC_CFG
15894 * 'termination' field appropriately.
15895 */
15896 if (eep_config.termination_se == 0) {
15897 termination = 0; /* auto termination for SE */
15898 } else {
15899 /* Enable manual control with low off / high off. */
15900 if (eep_config.termination_se == 1) {
15901 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015902
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015903 /* Enable manual control with low off / high on. */
15904 } else if (eep_config.termination_se == 2) {
15905 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015906
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015907 /* Enable manual control with low on / high on. */
15908 } else if (eep_config.termination_se == 3) {
15909 termination = TERM_SE;
15910 } else {
15911 /*
15912 * The EEPROM 'termination_se' field contains a bad value.
15913 * Use automatic termination instead.
15914 */
15915 termination = 0;
15916 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15917 }
15918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015919
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015920 if (eep_config.termination_lvd == 0) {
15921 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
15922 } else {
15923 /* Enable manual control with low off / high off. */
15924 if (eep_config.termination_lvd == 1) {
15925 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015926
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015927 /* Enable manual control with low off / high on. */
15928 } else if (eep_config.termination_lvd == 2) {
15929 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015930
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015931 /* Enable manual control with low on / high on. */
15932 } else if (eep_config.termination_lvd == 3) {
15933 asc_dvc->cfg->termination = termination | TERM_LVD;
15934 } else {
15935 /*
15936 * The EEPROM 'termination_lvd' field contains a bad value.
15937 * Use automatic termination instead.
15938 */
15939 asc_dvc->cfg->termination = termination;
15940 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15941 }
15942 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015943
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015944 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015945}
15946
15947/*
15948 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
15949 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
15950 * all of this is done.
15951 *
15952 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15953 *
15954 * For a non-fatal error return a warning code. If there are no warnings
15955 * then 0 is returned.
15956 *
15957 * Note: Chip is stopped on entry.
15958 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015959static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015960{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015961 AdvPortAddr iop_base;
15962 ushort warn_code;
15963 ADVEEP_38C1600_CONFIG eep_config;
15964 int i;
15965 uchar tid, termination;
15966 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015967
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015968 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015969
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015970 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015971
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015972 /*
15973 * Read the board's EEPROM configuration.
15974 *
15975 * Set default values if a bad checksum is found.
15976 */
15977 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
15978 eep_config.check_sum) {
15979 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015980
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015981 /*
15982 * Set EEPROM default values.
15983 */
15984 for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
15985 if (i == 1
15986 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
15987 0) {
15988 /*
15989 * Set Function 1 EEPROM Word 0 MSB
15990 *
15991 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
15992 * EEPROM bits.
15993 *
15994 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
15995 * old Mac system booting problem. The Expansion ROM must
15996 * be disabled in Function 1 for these systems.
15997 *
15998 */
15999 *((uchar *)&eep_config + i) =
16000 ((*
16001 ((uchar *)&Default_38C1600_EEPROM_Config
16002 +
16003 i)) &
16004 (~
16005 (((ADV_EEPROM_BIOS_ENABLE |
16006 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016007
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016008 /*
16009 * Set the INTAB (bit 11) if the GPIO 0 input indicates
16010 * the Function 1 interrupt line is wired to INTA.
16011 *
16012 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
16013 * 1 - Function 1 interrupt line wired to INT A.
16014 * 0 - Function 1 interrupt line wired to INT B.
16015 *
16016 * Note: Adapter boards always have Function 0 wired to INTA.
16017 * Put all 5 GPIO bits in input mode and then read
16018 * their input values.
16019 */
16020 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
16021 0);
16022 if (AdvReadByteRegister
16023 (iop_base, IOPB_GPIO_DATA) & 0x01) {
16024 /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
16025 *((uchar *)&eep_config + i) |=
16026 ((ADV_EEPROM_INTAB >> 8) & 0xFF);
16027 }
16028 } else {
16029 *((uchar *)&eep_config + i) =
16030 *((uchar *)&Default_38C1600_EEPROM_Config
16031 + i);
16032 }
16033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016034
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016035 /*
16036 * Assume the 6 byte board serial number that was read
16037 * from EEPROM is correct even if the EEPROM checksum
16038 * failed.
16039 */
16040 eep_config.serial_number_word3 =
16041 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016042
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016043 eep_config.serial_number_word2 =
16044 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016045
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016046 eep_config.serial_number_word1 =
16047 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016048
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016049 AdvSet38C1600EEPConfig(iop_base, &eep_config);
16050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016051
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016052 /*
16053 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
16054 * EEPROM configuration that was read.
16055 *
16056 * This is the mapping of EEPROM fields to Adv Library fields.
16057 */
16058 asc_dvc->wdtr_able = eep_config.wdtr_able;
16059 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
16060 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
16061 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
16062 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
16063 asc_dvc->ppr_able = 0;
16064 asc_dvc->tagqng_able = eep_config.tagqng_able;
16065 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16066 asc_dvc->max_host_qng = eep_config.max_host_qng;
16067 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16068 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
16069 asc_dvc->start_motor = eep_config.start_motor;
16070 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16071 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16072 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016073
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016074 /*
16075 * For every Target ID if any of its 'sdtr_speed[1234]' bits
16076 * are set, then set an 'sdtr_able' bit for it.
16077 */
16078 asc_dvc->sdtr_able = 0;
16079 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
16080 if (tid == 0) {
16081 sdtr_speed = asc_dvc->sdtr_speed1;
16082 } else if (tid == 4) {
16083 sdtr_speed = asc_dvc->sdtr_speed2;
16084 } else if (tid == 8) {
16085 sdtr_speed = asc_dvc->sdtr_speed3;
16086 } else if (tid == 12) {
16087 sdtr_speed = asc_dvc->sdtr_speed4;
16088 }
16089 if (sdtr_speed & ASC_MAX_TID) {
16090 asc_dvc->sdtr_able |= (1 << tid);
16091 }
16092 sdtr_speed >>= 4;
16093 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016094
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016095 /*
16096 * Set the host maximum queuing (max. 253, min. 16) and the per device
16097 * maximum queuing (max. 63, min. 4).
16098 */
16099 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16100 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16101 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16102 /* If the value is zero, assume it is uninitialized. */
16103 if (eep_config.max_host_qng == 0) {
16104 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16105 } else {
16106 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16107 }
16108 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016109
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016110 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16111 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16112 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16113 /* If the value is zero, assume it is uninitialized. */
16114 if (eep_config.max_dvc_qng == 0) {
16115 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16116 } else {
16117 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16118 }
16119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016120
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016121 /*
16122 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16123 * set 'max_dvc_qng' to 'max_host_qng'.
16124 */
16125 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16126 eep_config.max_dvc_qng = eep_config.max_host_qng;
16127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016128
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016129 /*
16130 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
16131 * values based on possibly adjusted EEPROM values.
16132 */
16133 asc_dvc->max_host_qng = eep_config.max_host_qng;
16134 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016135
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016136 /*
16137 * If the EEPROM 'termination' field is set to automatic (0), then set
16138 * the ASC_DVC_CFG 'termination' field to automatic also.
16139 *
16140 * If the termination is specified with a non-zero 'termination'
16141 * value check that a legal value is set and set the ASC_DVC_CFG
16142 * 'termination' field appropriately.
16143 */
16144 if (eep_config.termination_se == 0) {
16145 termination = 0; /* auto termination for SE */
16146 } else {
16147 /* Enable manual control with low off / high off. */
16148 if (eep_config.termination_se == 1) {
16149 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016150
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016151 /* Enable manual control with low off / high on. */
16152 } else if (eep_config.termination_se == 2) {
16153 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016154
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016155 /* Enable manual control with low on / high on. */
16156 } else if (eep_config.termination_se == 3) {
16157 termination = TERM_SE;
16158 } else {
16159 /*
16160 * The EEPROM 'termination_se' field contains a bad value.
16161 * Use automatic termination instead.
16162 */
16163 termination = 0;
16164 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16165 }
16166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016167
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016168 if (eep_config.termination_lvd == 0) {
16169 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16170 } else {
16171 /* Enable manual control with low off / high off. */
16172 if (eep_config.termination_lvd == 1) {
16173 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016174
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016175 /* Enable manual control with low off / high on. */
16176 } else if (eep_config.termination_lvd == 2) {
16177 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016178
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016179 /* Enable manual control with low on / high on. */
16180 } else if (eep_config.termination_lvd == 3) {
16181 asc_dvc->cfg->termination = termination | TERM_LVD;
16182 } else {
16183 /*
16184 * The EEPROM 'termination_lvd' field contains a bad value.
16185 * Use automatic termination instead.
16186 */
16187 asc_dvc->cfg->termination = termination;
16188 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16189 }
16190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016191
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016192 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016193}
16194
16195/*
16196 * Read EEPROM configuration into the specified buffer.
16197 *
16198 * Return a checksum based on the EEPROM configuration read.
16199 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016200static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016201AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16202{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016203 ushort wval, chksum;
16204 ushort *wbuf;
16205 int eep_addr;
16206 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016207
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016208 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16209 wbuf = (ushort *)cfg_buf;
16210 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016211
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016212 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16213 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16214 wval = AdvReadEEPWord(iop_base, eep_addr);
16215 chksum += wval; /* Checksum is calculated from word values. */
16216 if (*charfields++) {
16217 *wbuf = le16_to_cpu(wval);
16218 } else {
16219 *wbuf = wval;
16220 }
16221 }
16222 /* Read checksum word. */
16223 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16224 wbuf++;
16225 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016226
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016227 /* Read rest of EEPROM not covered by the checksum. */
16228 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16229 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16230 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16231 if (*charfields++) {
16232 *wbuf = le16_to_cpu(*wbuf);
16233 }
16234 }
16235 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016236}
16237
16238/*
16239 * Read EEPROM configuration into the specified buffer.
16240 *
16241 * Return a checksum based on the EEPROM configuration read.
16242 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016243static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016244AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016245{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016246 ushort wval, chksum;
16247 ushort *wbuf;
16248 int eep_addr;
16249 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016250
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016251 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16252 wbuf = (ushort *)cfg_buf;
16253 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016254
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016255 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16256 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16257 wval = AdvReadEEPWord(iop_base, eep_addr);
16258 chksum += wval; /* Checksum is calculated from word values. */
16259 if (*charfields++) {
16260 *wbuf = le16_to_cpu(wval);
16261 } else {
16262 *wbuf = wval;
16263 }
16264 }
16265 /* Read checksum word. */
16266 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16267 wbuf++;
16268 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016269
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016270 /* Read rest of EEPROM not covered by the checksum. */
16271 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16272 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16273 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16274 if (*charfields++) {
16275 *wbuf = le16_to_cpu(*wbuf);
16276 }
16277 }
16278 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016279}
16280
16281/*
16282 * Read EEPROM configuration into the specified buffer.
16283 *
16284 * Return a checksum based on the EEPROM configuration read.
16285 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016286static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016287AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016288{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016289 ushort wval, chksum;
16290 ushort *wbuf;
16291 int eep_addr;
16292 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016293
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016294 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16295 wbuf = (ushort *)cfg_buf;
16296 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016297
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016298 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16299 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16300 wval = AdvReadEEPWord(iop_base, eep_addr);
16301 chksum += wval; /* Checksum is calculated from word values. */
16302 if (*charfields++) {
16303 *wbuf = le16_to_cpu(wval);
16304 } else {
16305 *wbuf = wval;
16306 }
16307 }
16308 /* Read checksum word. */
16309 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16310 wbuf++;
16311 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016312
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016313 /* Read rest of EEPROM not covered by the checksum. */
16314 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16315 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16316 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16317 if (*charfields++) {
16318 *wbuf = le16_to_cpu(*wbuf);
16319 }
16320 }
16321 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016322}
16323
16324/*
16325 * Read the EEPROM from specified location
16326 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016327static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016328{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016329 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16330 ASC_EEP_CMD_READ | eep_word_addr);
16331 AdvWaitEEPCmd(iop_base);
16332 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016333}
16334
16335/*
16336 * Wait for EEPROM command to complete
16337 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016338static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016339{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016340 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016341
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016342 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16343 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16344 ASC_EEP_CMD_DONE) {
16345 break;
16346 }
16347 DvcSleepMilliSecond(1);
16348 }
16349 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16350 0) {
16351 ASC_ASSERT(0);
16352 }
16353 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016354}
16355
16356/*
16357 * Write the EEPROM from 'cfg_buf'.
16358 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016359void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016360AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16361{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016362 ushort *wbuf;
16363 ushort addr, chksum;
16364 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016365
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016366 wbuf = (ushort *)cfg_buf;
16367 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16368 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016369
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016370 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16371 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016372
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016373 /*
16374 * Write EEPROM from word 0 to word 20.
16375 */
16376 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16377 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16378 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016379
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016380 if (*charfields++) {
16381 word = cpu_to_le16(*wbuf);
16382 } else {
16383 word = *wbuf;
16384 }
16385 chksum += *wbuf; /* Checksum is calculated from word values. */
16386 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16387 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16388 ASC_EEP_CMD_WRITE | addr);
16389 AdvWaitEEPCmd(iop_base);
16390 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016392
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016393 /*
16394 * Write EEPROM checksum at word 21.
16395 */
16396 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16397 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16398 AdvWaitEEPCmd(iop_base);
16399 wbuf++;
16400 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016401
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016402 /*
16403 * Write EEPROM OEM name at words 22 to 29.
16404 */
16405 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16406 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16407 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016408
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016409 if (*charfields++) {
16410 word = cpu_to_le16(*wbuf);
16411 } else {
16412 word = *wbuf;
16413 }
16414 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16415 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16416 ASC_EEP_CMD_WRITE | addr);
16417 AdvWaitEEPCmd(iop_base);
16418 }
16419 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16420 AdvWaitEEPCmd(iop_base);
16421 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016422}
16423
16424/*
16425 * Write the EEPROM from 'cfg_buf'.
16426 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016427void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016428AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016429{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016430 ushort *wbuf;
16431 ushort *charfields;
16432 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016433
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016434 wbuf = (ushort *)cfg_buf;
16435 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16436 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016437
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016438 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16439 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016441 /*
16442 * Write EEPROM from word 0 to word 20.
16443 */
16444 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16445 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16446 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016447
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016448 if (*charfields++) {
16449 word = cpu_to_le16(*wbuf);
16450 } else {
16451 word = *wbuf;
16452 }
16453 chksum += *wbuf; /* Checksum is calculated from word values. */
16454 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16455 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16456 ASC_EEP_CMD_WRITE | addr);
16457 AdvWaitEEPCmd(iop_base);
16458 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016460
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016461 /*
16462 * Write EEPROM checksum at word 21.
16463 */
16464 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16465 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16466 AdvWaitEEPCmd(iop_base);
16467 wbuf++;
16468 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016469
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016470 /*
16471 * Write EEPROM OEM name at words 22 to 29.
16472 */
16473 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16474 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16475 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016476
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016477 if (*charfields++) {
16478 word = cpu_to_le16(*wbuf);
16479 } else {
16480 word = *wbuf;
16481 }
16482 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16483 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16484 ASC_EEP_CMD_WRITE | addr);
16485 AdvWaitEEPCmd(iop_base);
16486 }
16487 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16488 AdvWaitEEPCmd(iop_base);
16489 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016490}
16491
16492/*
16493 * Write the EEPROM from 'cfg_buf'.
16494 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016495void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016496AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016497{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016498 ushort *wbuf;
16499 ushort *charfields;
16500 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016501
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016502 wbuf = (ushort *)cfg_buf;
16503 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16504 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016505
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016506 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16507 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016508
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016509 /*
16510 * Write EEPROM from word 0 to word 20.
16511 */
16512 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16513 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16514 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016515
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016516 if (*charfields++) {
16517 word = cpu_to_le16(*wbuf);
16518 } else {
16519 word = *wbuf;
16520 }
16521 chksum += *wbuf; /* Checksum is calculated from word values. */
16522 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16523 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16524 ASC_EEP_CMD_WRITE | addr);
16525 AdvWaitEEPCmd(iop_base);
16526 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016528
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016529 /*
16530 * Write EEPROM checksum at word 21.
16531 */
16532 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16533 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16534 AdvWaitEEPCmd(iop_base);
16535 wbuf++;
16536 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016537
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016538 /*
16539 * Write EEPROM OEM name at words 22 to 29.
16540 */
16541 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16542 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16543 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016544
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016545 if (*charfields++) {
16546 word = cpu_to_le16(*wbuf);
16547 } else {
16548 word = *wbuf;
16549 }
16550 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16551 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16552 ASC_EEP_CMD_WRITE | addr);
16553 AdvWaitEEPCmd(iop_base);
16554 }
16555 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16556 AdvWaitEEPCmd(iop_base);
16557 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016558}
16559
16560/* a_advlib.c */
16561/*
16562 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
16563 *
16564 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
16565 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
16566 * RISC to notify it a new command is ready to be executed.
16567 *
16568 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
16569 * set to SCSI_MAX_RETRY.
16570 *
16571 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
16572 * for DMA addresses or math operations are byte swapped to little-endian
16573 * order.
16574 *
16575 * Return:
16576 * ADV_SUCCESS(1) - The request was successfully queued.
16577 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
16578 * request completes.
16579 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
16580 * host IC error.
16581 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016582static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016583{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016584 ulong last_int_level;
16585 AdvPortAddr iop_base;
16586 ADV_DCNT req_size;
16587 ADV_PADDR req_paddr;
16588 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016589
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016590 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016591
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016592 /*
16593 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
16594 */
16595 if (scsiq->target_id > ADV_MAX_TID) {
16596 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
16597 scsiq->done_status = QD_WITH_ERROR;
16598 return ADV_ERROR;
16599 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016600
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016601 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016602
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016603 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016604
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016605 /*
16606 * Allocate a carrier ensuring at least one carrier always
16607 * remains on the freelist and initialize fields.
16608 */
16609 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
16610 DvcLeaveCritical(last_int_level);
16611 return ADV_BUSY;
16612 }
16613 asc_dvc->carr_freelist = (ADV_CARR_T *)
16614 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
16615 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016616
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016617 /*
16618 * Set the carrier to be a stopper by setting 'next_vpa'
16619 * to the stopper value. The current stopper will be changed
16620 * below to point to the new stopper.
16621 */
16622 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016623
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016624 /*
16625 * Clear the ADV_SCSI_REQ_Q done flag.
16626 */
16627 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016628
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016629 req_size = sizeof(ADV_SCSI_REQ_Q);
16630 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
16631 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016632
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016633 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
16634 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016635
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016636 /* Wait for assertion before making little-endian */
16637 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016638
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016639 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
16640 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
16641 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016643 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
16644 /*
16645 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
16646 * order during initialization.
16647 */
16648 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016649
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016650 /*
16651 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
16652 * the microcode. The newly allocated stopper will become the new
16653 * stopper.
16654 */
16655 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016657 /*
16658 * Set the 'next_vpa' pointer for the old stopper to be the
16659 * physical address of the new stopper. The RISC can only
16660 * follow physical addresses.
16661 */
16662 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016663
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016664 /*
16665 * Set the host adapter stopper pointer to point to the new carrier.
16666 */
16667 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016668
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016669 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16670 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16671 /*
16672 * Tickle the RISC to tell it to read its Command Queue Head pointer.
16673 */
16674 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
16675 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16676 /*
16677 * Clear the tickle value. In the ASC-3550 the RISC flag
16678 * command 'clr_tickle_a' does not work unless the host
16679 * value is cleared.
16680 */
16681 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16682 ADV_TICKLE_NOP);
16683 }
16684 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16685 /*
16686 * Notify the RISC a carrier is ready by writing the physical
16687 * address of the new carrier stopper to the COMMA register.
16688 */
16689 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
16690 le32_to_cpu(new_carrp->carr_pa));
16691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016692
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016693 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016694
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016695 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016696}
16697
16698/*
16699 * Reset SCSI Bus and purge all outstanding requests.
16700 *
16701 * Return Value:
16702 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
16703 * ADV_FALSE(0) - Microcode command failed.
16704 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
16705 * may be hung which requires driver recovery.
16706 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016707static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016708{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016709 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016710
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016711 /*
16712 * Send the SCSI Bus Reset idle start idle command which asserts
16713 * the SCSI Bus Reset signal.
16714 */
16715 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
16716 if (status != ADV_TRUE) {
16717 return status;
16718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016719
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016720 /*
16721 * Delay for the specified SCSI Bus Reset hold time.
16722 *
16723 * The hold time delay is done on the host because the RISC has no
16724 * microsecond accurate timer.
16725 */
16726 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016727
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016728 /*
16729 * Send the SCSI Bus Reset end idle command which de-asserts
16730 * the SCSI Bus Reset signal and purges any pending requests.
16731 */
16732 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
16733 if (status != ADV_TRUE) {
16734 return status;
16735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016736
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016737 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016738
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016739 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016740}
16741
16742/*
16743 * Reset chip and SCSI Bus.
16744 *
16745 * Return Value:
16746 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
16747 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
16748 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016749static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016750{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016751 int status;
16752 ushort wdtr_able, sdtr_able, tagqng_able;
16753 ushort ppr_able = 0;
16754 uchar tid, max_cmd[ADV_MAX_TID + 1];
16755 AdvPortAddr iop_base;
16756 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016757
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016758 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016759
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016760 /*
16761 * Save current per TID negotiated values.
16762 */
16763 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16764 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16765 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16766 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16767 }
16768 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16769 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16770 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16771 max_cmd[tid]);
16772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016773
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016774 /*
16775 * Force the AdvInitAsc3550/38C0800Driver() function to
16776 * perform a SCSI Bus Reset by clearing the BIOS signature word.
16777 * The initialization functions assumes a SCSI Bus Reset is not
16778 * needed if the BIOS signature word is present.
16779 */
16780 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
16781 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016782
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016783 /*
16784 * Stop chip and reset it.
16785 */
16786 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
16787 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
16788 DvcSleepMilliSecond(100);
16789 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
16790 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016791
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016792 /*
16793 * Reset Adv Library error code, if any, and try
16794 * re-initializing the chip.
16795 */
16796 asc_dvc->err_code = 0;
16797 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16798 status = AdvInitAsc38C1600Driver(asc_dvc);
16799 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16800 status = AdvInitAsc38C0800Driver(asc_dvc);
16801 } else {
16802 status = AdvInitAsc3550Driver(asc_dvc);
16803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016804
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016805 /* Translate initialization return value to status value. */
16806 if (status == 0) {
16807 status = ADV_TRUE;
16808 } else {
16809 status = ADV_FALSE;
16810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016811
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016812 /*
16813 * Restore the BIOS signature word.
16814 */
16815 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016816
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016817 /*
16818 * Restore per TID negotiated values.
16819 */
16820 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16821 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16822 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16823 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16824 }
16825 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16826 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16827 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16828 max_cmd[tid]);
16829 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016830
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016831 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016832}
16833
16834/*
16835 * Adv Library Interrupt Service Routine
16836 *
16837 * This function is called by a driver's interrupt service routine.
16838 * The function disables and re-enables interrupts.
16839 *
16840 * When a microcode idle command is completed, the ADV_DVC_VAR
16841 * 'idle_cmd_done' field is set to ADV_TRUE.
16842 *
16843 * Note: AdvISR() can be called when interrupts are disabled or even
16844 * when there is no hardware interrupt condition present. It will
16845 * always check for completed idle commands and microcode requests.
16846 * This is an important feature that shouldn't be changed because it
16847 * allows commands to be completed from polling mode loops.
16848 *
16849 * Return:
16850 * ADV_TRUE(1) - interrupt was pending
16851 * ADV_FALSE(0) - no interrupt was pending
16852 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016853static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016854{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016855 AdvPortAddr iop_base;
16856 uchar int_stat;
16857 ushort target_bit;
16858 ADV_CARR_T *free_carrp;
16859 ADV_VADDR irq_next_vpa;
16860 int flags;
16861 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016862
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016863 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016864
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016865 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016866
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016867 /* Reading the register clears the interrupt. */
16868 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016869
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016870 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
16871 ADV_INTR_STATUS_INTRC)) == 0) {
16872 DvcLeaveCritical(flags);
16873 return ADV_FALSE;
16874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016875
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016876 /*
16877 * Notify the driver of an asynchronous microcode condition by
16878 * calling the ADV_DVC_VAR.async_callback function. The function
16879 * is passed the microcode ASC_MC_INTRB_CODE byte value.
16880 */
16881 if (int_stat & ADV_INTR_STATUS_INTRB) {
16882 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016883
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016884 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016885
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016886 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16887 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16888 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
16889 asc_dvc->carr_pending_cnt != 0) {
16890 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16891 ADV_TICKLE_A);
16892 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16893 AdvWriteByteRegister(iop_base,
16894 IOPB_TICKLE,
16895 ADV_TICKLE_NOP);
16896 }
16897 }
16898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016899
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016900 if (asc_dvc->async_callback != 0) {
16901 (*asc_dvc->async_callback) (asc_dvc, intrb_code);
16902 }
16903 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016904
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016905 /*
16906 * Check if the IRQ stopper carrier contains a completed request.
16907 */
16908 while (((irq_next_vpa =
16909 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
16910 /*
16911 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
16912 * The RISC will have set 'areq_vpa' to a virtual address.
16913 *
16914 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
16915 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
16916 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
16917 * in AdvExeScsiQueue().
16918 */
16919 scsiq = (ADV_SCSI_REQ_Q *)
16920 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016921
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016922 /*
16923 * Request finished with good status and the queue was not
16924 * DMAed to host memory by the firmware. Set all status fields
16925 * to indicate good status.
16926 */
16927 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
16928 scsiq->done_status = QD_NO_ERROR;
16929 scsiq->host_status = scsiq->scsi_status = 0;
16930 scsiq->data_cnt = 0L;
16931 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016932
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016933 /*
16934 * Advance the stopper pointer to the next carrier
16935 * ignoring the lower four bits. Free the previous
16936 * stopper carrier.
16937 */
16938 free_carrp = asc_dvc->irq_sp;
16939 asc_dvc->irq_sp = (ADV_CARR_T *)
16940 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016941
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016942 free_carrp->next_vpa =
16943 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
16944 asc_dvc->carr_freelist = free_carrp;
16945 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016946
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016947 ASC_ASSERT(scsiq != NULL);
16948 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016949
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016950 /*
16951 * Clear request microcode control flag.
16952 */
16953 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016954
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016955 /*
16956 * If the command that completed was a SCSI INQUIRY and
16957 * LUN 0 was sent the command, then process the INQUIRY
16958 * command information for the device.
16959 *
16960 * Note: If data returned were either VPD or CmdDt data,
16961 * don't process the INQUIRY command information for
16962 * the device, otherwise may erroneously set *_able bits.
16963 */
16964 if (scsiq->done_status == QD_NO_ERROR &&
16965 scsiq->cdb[0] == INQUIRY &&
16966 scsiq->target_lun == 0 &&
16967 (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
16968 == ADV_INQ_RTN_STD_INQUIRY_DATA) {
16969 AdvInquiryHandling(asc_dvc, scsiq);
16970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016971
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016972 /*
16973 * Notify the driver of the completed request by passing
16974 * the ADV_SCSI_REQ_Q pointer to its callback function.
16975 */
16976 scsiq->a_flag |= ADV_SCSIQ_DONE;
16977 (*asc_dvc->isr_callback) (asc_dvc, scsiq);
16978 /*
16979 * Note: After the driver callback function is called, 'scsiq'
16980 * can no longer be referenced.
16981 *
16982 * Fall through and continue processing other completed
16983 * requests...
16984 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016985
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016986 /*
16987 * Disable interrupts again in case the driver inadvertently
16988 * enabled interrupts in its callback function.
16989 *
16990 * The DvcEnterCritical() return value is ignored, because
16991 * the 'flags' saved when AdvISR() was first entered will be
16992 * used to restore the interrupt flag on exit.
16993 */
16994 (void)DvcEnterCritical();
16995 }
16996 DvcLeaveCritical(flags);
16997 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016998}
16999
17000/*
17001 * Send an idle command to the chip and wait for completion.
17002 *
17003 * Command completion is polled for once per microsecond.
17004 *
17005 * The function can be called from anywhere including an interrupt handler.
17006 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
17007 * functions to prevent reentrancy.
17008 *
17009 * Return Values:
17010 * ADV_TRUE - command completed successfully
17011 * ADV_FALSE - command failed
17012 * ADV_ERROR - command timed out
17013 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017014static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070017015AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017016 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017017{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017018 ulong last_int_level;
17019 int result;
17020 ADV_DCNT i, j;
17021 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017022
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017023 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017024
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017025 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017026
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017027 /*
17028 * Clear the idle command status which is set by the microcode
17029 * to a non-zero value to indicate when the command is completed.
17030 * The non-zero result is one of the IDLE_CMD_STATUS_* values
17031 * defined in a_advlib.h.
17032 */
17033 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017034
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017035 /*
17036 * Write the idle command value after the idle command parameter
17037 * has been written to avoid a race condition. If the order is not
17038 * followed, the microcode may process the idle command before the
17039 * parameters have been written to LRAM.
17040 */
17041 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
17042 cpu_to_le32(idle_cmd_parameter));
17043 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017044
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017045 /*
17046 * Tickle the RISC to tell it to process the idle command.
17047 */
17048 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
17049 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17050 /*
17051 * Clear the tickle value. In the ASC-3550 the RISC flag
17052 * command 'clr_tickle_b' does not work unless the host
17053 * value is cleared.
17054 */
17055 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
17056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017057
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017058 /* Wait for up to 100 millisecond for the idle command to timeout. */
17059 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
17060 /* Poll once each microsecond for command completion. */
17061 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
17062 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
17063 result);
17064 if (result != 0) {
17065 DvcLeaveCritical(last_int_level);
17066 return result;
17067 }
17068 DvcDelayMicroSecond(asc_dvc, (ushort)1);
17069 }
17070 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017071
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017072 ASC_ASSERT(0); /* The idle command should never timeout. */
17073 DvcLeaveCritical(last_int_level);
17074 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017075}
17076
17077/*
17078 * Inquiry Information Byte 7 Handling
17079 *
17080 * Handle SCSI Inquiry Command information for a device by setting
17081 * microcode operating variables that affect WDTR, SDTR, and Tag
17082 * Queuing.
17083 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017084static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017085{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017086 AdvPortAddr iop_base;
17087 uchar tid;
17088 ADV_SCSI_INQUIRY *inq;
17089 ushort tidmask;
17090 ushort cfg_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017091
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017092 /*
17093 * AdvInquiryHandling() requires up to INQUIRY information Byte 7
17094 * to be available.
17095 *
17096 * If less than 8 bytes of INQUIRY information were requested or less
17097 * than 8 bytes were transferred, then return. cdb[4] is the request
17098 * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
17099 * microcode to the transfer residual count.
17100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017101
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017102 if (scsiq->cdb[4] < 8 ||
17103 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) {
17104 return;
17105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017106
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017107 iop_base = asc_dvc->iop_base;
17108 tid = scsiq->target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017109
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017110 inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017111
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017112 /*
17113 * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
17114 */
17115 if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) {
17116 return;
17117 } else {
17118 /*
17119 * INQUIRY Byte 7 Handling
17120 *
17121 * Use a device's INQUIRY byte 7 to determine whether it
17122 * supports WDTR, SDTR, and Tag Queuing. If the feature
17123 * is enabled in the EEPROM and the device supports the
17124 * feature, then enable it in the microcode.
17125 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017126
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017127 tidmask = ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017128
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017129 /*
17130 * Wide Transfers
17131 *
17132 * If the EEPROM enabled WDTR for the device and the device
17133 * supports wide bus (16 bit) transfers, then turn on the
17134 * device's 'wdtr_able' bit and write the new value to the
17135 * microcode.
17136 */
17137 if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) {
17138 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
17139 if ((cfg_word & tidmask) == 0) {
17140 cfg_word |= tidmask;
17141 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
17142 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017143
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017144 /*
17145 * Clear the microcode "SDTR negotiation" and "WDTR
17146 * negotiation" done indicators for the target to cause
17147 * it to negotiate with the new setting set above.
17148 * WDTR when accepted causes the target to enter
17149 * asynchronous mode, so SDTR must be negotiated.
17150 */
17151 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17152 cfg_word);
17153 cfg_word &= ~tidmask;
17154 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17155 cfg_word);
17156 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE,
17157 cfg_word);
17158 cfg_word &= ~tidmask;
17159 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE,
17160 cfg_word);
17161 }
17162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017163
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017164 /*
17165 * Synchronous Transfers
17166 *
17167 * If the EEPROM enabled SDTR for the device and the device
17168 * supports synchronous transfers, then turn on the device's
17169 * 'sdtr_able' bit. Write the new value to the microcode.
17170 */
17171 if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) {
17172 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
17173 if ((cfg_word & tidmask) == 0) {
17174 cfg_word |= tidmask;
17175 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
17176 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017177
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017178 /*
17179 * Clear the microcode "SDTR negotiation" done indicator
17180 * for the target to cause it to negotiate with the new
17181 * setting set above.
17182 */
17183 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17184 cfg_word);
17185 cfg_word &= ~tidmask;
17186 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17187 cfg_word);
17188 }
17189 }
17190 /*
17191 * If the Inquiry data included enough space for the SPI-3
17192 * Clocking field, then check if DT mode is supported.
17193 */
17194 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
17195 (scsiq->cdb[4] >= 57 ||
17196 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) {
17197 /*
17198 * PPR (Parallel Protocol Request) Capable
17199 *
17200 * If the device supports DT mode, then it must be PPR capable.
17201 * The PPR message will be used in place of the SDTR and WDTR
17202 * messages to negotiate synchronous speed and offset, transfer
17203 * width, and protocol options.
17204 */
17205 if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) {
17206 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE,
17207 asc_dvc->ppr_able);
17208 asc_dvc->ppr_able |= tidmask;
17209 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE,
17210 asc_dvc->ppr_able);
17211 }
17212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017213
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017214 /*
17215 * If the EEPROM enabled Tag Queuing for the device and the
17216 * device supports Tag Queueing, then turn on the device's
17217 * 'tagqng_enable' bit in the microcode and set the microcode
17218 * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
17219 * value.
17220 *
17221 * Tag Queuing is disabled for the BIOS which runs in polled
17222 * mode and would see no benefit from Tag Queuing. Also by
17223 * disabling Tag Queuing in the BIOS devices with Tag Queuing
17224 * bugs will at least work with the BIOS.
17225 */
17226 if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) {
17227 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
17228 cfg_word |= tidmask;
17229 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
17230 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017231
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017232 AdvWriteByteLram(iop_base,
17233 ASC_MC_NUMBER_OF_MAX_CMD + tid,
17234 asc_dvc->max_dvc_qng);
17235 }
17236 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017237}
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017238
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017239static int __devinit
17240advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
17241{
17242 int req_cnt = 0;
17243 adv_req_t *reqp = NULL;
17244 int sg_cnt = 0;
17245 adv_sgblk_t *sgp;
17246 int warn_code, err_code;
17247
17248 /*
17249 * Allocate buffer carrier structures. The total size
17250 * is about 4 KB, so allocate all at once.
17251 */
17252 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
17253 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
17254
17255 if (!boardp->carrp)
17256 goto kmalloc_failed;
17257
17258 /*
17259 * Allocate up to 'max_host_qng' request structures for the Wide
17260 * board. The total size is about 16 KB, so allocate all at once.
17261 * If the allocation fails decrement and try again.
17262 */
17263 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
17264 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
17265
17266 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
17267 "bytes %lu\n", reqp, req_cnt,
17268 (ulong)sizeof(adv_req_t) * req_cnt);
17269
17270 if (reqp)
17271 break;
17272 }
17273
17274 if (!reqp)
17275 goto kmalloc_failed;
17276
17277 boardp->orig_reqp = reqp;
17278
17279 /*
17280 * Allocate up to ADV_TOT_SG_BLOCK request structures for
17281 * the Wide board. Each structure is about 136 bytes.
17282 */
17283 boardp->adv_sgblkp = NULL;
17284 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
17285 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
17286
17287 if (!sgp)
17288 break;
17289
17290 sgp->next_sgblkp = boardp->adv_sgblkp;
17291 boardp->adv_sgblkp = sgp;
17292
17293 }
17294
17295 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
17296 sg_cnt, sizeof(adv_sgblk_t),
17297 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
17298
17299 if (!boardp->adv_sgblkp)
17300 goto kmalloc_failed;
17301
17302 adv_dvc_varp->carrier_buf = boardp->carrp;
17303
17304 /*
17305 * Point 'adv_reqp' to the request structures and
17306 * link them together.
17307 */
17308 req_cnt--;
17309 reqp[req_cnt].next_reqp = NULL;
17310 for (; req_cnt > 0; req_cnt--) {
17311 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
17312 }
17313 boardp->adv_reqp = &reqp[0];
17314
17315 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17316 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
17317 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
17318 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17319 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
17320 "\n");
17321 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
17322 } else {
17323 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
17324 "\n");
17325 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
17326 }
17327 err_code = adv_dvc_varp->err_code;
17328
17329 if (warn_code || err_code) {
17330 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
17331 " error 0x%x\n", boardp->id, warn_code, err_code);
17332 }
17333
17334 goto exit;
17335
17336 kmalloc_failed:
17337 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
17338 "failed\n", boardp->id);
17339 err_code = ADV_ERROR;
17340 exit:
17341 return err_code;
17342}
17343
17344static void advansys_wide_free_mem(asc_board_t *boardp)
17345{
17346 kfree(boardp->carrp);
17347 boardp->carrp = NULL;
17348 kfree(boardp->orig_reqp);
17349 boardp->orig_reqp = boardp->adv_reqp = NULL;
17350 while (boardp->adv_sgblkp) {
17351 adv_sgblk_t *sgp = boardp->adv_sgblkp;
17352 boardp->adv_sgblkp = sgp->next_sgblkp;
17353 kfree(sgp);
17354 }
17355}
17356
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017357static struct Scsi_Host *__devinit
17358advansys_board_found(int iop, struct device *dev, int bus_type)
17359{
17360 struct Scsi_Host *shost;
17361 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
17362 asc_board_t *boardp;
17363 ASC_DVC_VAR *asc_dvc_varp = NULL;
17364 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017365 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017366 int iolen = 0;
17367 ADV_PADDR pci_memory_address;
17368 int warn_code, err_code;
17369 int ret;
17370
17371 /*
17372 * Adapter found.
17373 *
17374 * Register the adapter, get its configuration, and
17375 * initialize it.
17376 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017377 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
17378 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017379
17380 if (!shost)
17381 return NULL;
17382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017383 /* Initialize private per board data */
17384 boardp = ASC_BOARDP(shost);
17385 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017386 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017387
17388 /* Initialize spinlock. */
17389 spin_lock_init(&boardp->lock);
17390
17391 /*
17392 * Handle both narrow and wide boards.
17393 *
17394 * If a Wide board was detected, set the board structure
17395 * wide board flag. Set-up the board structure based on
17396 * the board type.
17397 */
17398#ifdef CONFIG_PCI
17399 if (bus_type == ASC_IS_PCI &&
17400 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17401 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17402 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17403 boardp->flags |= ASC_IS_WIDE_BOARD;
17404 }
17405#endif /* CONFIG_PCI */
17406
17407 if (ASC_NARROW_BOARD(boardp)) {
17408 ASC_DBG(1, "advansys_board_found: narrow board\n");
17409 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17410 asc_dvc_varp->bus_type = bus_type;
17411 asc_dvc_varp->drv_ptr = boardp;
17412 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17413 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17414 asc_dvc_varp->iop_base = iop;
17415 asc_dvc_varp->isr_callback = asc_isr_callback;
17416 } else {
17417 ASC_DBG(1, "advansys_board_found: wide board\n");
17418 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17419 adv_dvc_varp->drv_ptr = boardp;
17420 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
17421 adv_dvc_varp->isr_callback = adv_isr_callback;
17422 adv_dvc_varp->async_callback = adv_async_callback;
17423#ifdef CONFIG_PCI
17424 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17425 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17426 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17427 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17428 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17429 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17430 } else {
17431 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17432 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17433 }
17434#endif /* CONFIG_PCI */
17435
17436 /*
17437 * Map the board's registers into virtual memory for
17438 * PCI slave access. Only memory accesses are used to
17439 * access the board's registers.
17440 *
17441 * Note: The PCI register base address is not always
17442 * page aligned, but the address passed to ioremap()
17443 * must be page aligned. It is guaranteed that the
17444 * PCI register base address will not cross a page
17445 * boundary.
17446 */
17447 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17448 iolen = ADV_3550_IOLEN;
17449 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17450 iolen = ADV_38C0800_IOLEN;
17451 } else {
17452 iolen = ADV_38C1600_IOLEN;
17453 }
17454#ifdef CONFIG_PCI
17455 pci_memory_address = pci_resource_start(pdev, 1);
17456 ASC_DBG1(1,
17457 "advansys_board_found: pci_memory_address: 0x%lx\n",
17458 (ulong)pci_memory_address);
17459 if ((boardp->ioremap_addr =
17460 ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
17461 ASC_PRINT3
17462 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
17463 boardp->id, pci_memory_address, iolen);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017464 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017465 }
Matthew Wilcox71f36112007-07-30 08:04:53 -060017466 ASC_DBG1(1, "advansys_board_found: ioremap_addr: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017467 (ulong)boardp->ioremap_addr);
17468 adv_dvc_varp->iop_base = (AdvPortAddr)
17469 (boardp->ioremap_addr +
17470 (pci_memory_address - (pci_memory_address & PAGE_MASK)));
Matthew Wilcox71f36112007-07-30 08:04:53 -060017471 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017472 adv_dvc_varp->iop_base);
17473#endif /* CONFIG_PCI */
17474
17475 /*
17476 * Even though it isn't used to access wide boards, other
17477 * than for the debug line below, save I/O Port address so
17478 * that it can be reported.
17479 */
17480 boardp->ioport = iop;
17481
17482 ASC_DBG2(1,
17483 "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
17484 (ushort)inp(iop + 1), (ushort)inpw(iop));
17485 }
17486
17487#ifdef CONFIG_PROC_FS
17488 /*
17489 * Allocate buffer for printing information from
17490 * /proc/scsi/advansys/[0...].
17491 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017492 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
17493 if (!boardp->prtbuf) {
17494 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
17495 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
17496 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017497 }
17498#endif /* CONFIG_PROC_FS */
17499
17500 if (ASC_NARROW_BOARD(boardp)) {
17501 asc_dvc_varp->cfg->dev = dev;
17502 /*
17503 * Set the board bus type and PCI IRQ before
17504 * calling AscInitGetConfig().
17505 */
17506 switch (asc_dvc_varp->bus_type) {
17507#ifdef CONFIG_ISA
17508 case ASC_IS_ISA:
17509 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017510 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017511 break;
17512 case ASC_IS_VL:
17513 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017514 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017515 break;
17516 case ASC_IS_EISA:
17517 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017518 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017519 break;
17520#endif /* CONFIG_ISA */
17521#ifdef CONFIG_PCI
17522 case ASC_IS_PCI:
17523 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
17524 asc_dvc_varp->cfg->pci_slot_info =
17525 ASC_PCI_MKID(pdev->bus->number,
17526 PCI_SLOT(pdev->devfn),
17527 PCI_FUNC(pdev->devfn));
17528 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017529 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017530 break;
17531#endif /* CONFIG_PCI */
17532 default:
17533 ASC_PRINT2
17534 ("advansys_board_found: board %d: unknown adapter type: %d\n",
17535 boardp->id, asc_dvc_varp->bus_type);
17536 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017537 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017538 break;
17539 }
17540 } else {
17541 adv_dvc_varp->cfg->dev = dev;
17542 /*
17543 * For Wide boards set PCI information before calling
17544 * AdvInitGetConfig().
17545 */
17546#ifdef CONFIG_PCI
17547 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
17548 adv_dvc_varp->cfg->pci_slot_info =
17549 ASC_PCI_MKID(pdev->bus->number,
17550 PCI_SLOT(pdev->devfn),
17551 PCI_FUNC(pdev->devfn));
17552 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017553 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017554#endif /* CONFIG_PCI */
17555 }
17556
17557 /*
17558 * Read the board configuration.
17559 */
17560 if (ASC_NARROW_BOARD(boardp)) {
17561 /*
17562 * NOTE: AscInitGetConfig() may change the board's
17563 * bus_type value. The bus_type value should no
17564 * longer be used. If the bus_type field must be
17565 * referenced only use the bit-wise AND operator "&".
17566 */
17567 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
17568 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
17569 case 0: /* No error */
17570 break;
17571 case ASC_WARN_IO_PORT_ROTATE:
17572 ASC_PRINT1
17573 ("AscInitGetConfig: board %d: I/O port address modified\n",
17574 boardp->id);
17575 break;
17576 case ASC_WARN_AUTO_CONFIG:
17577 ASC_PRINT1
17578 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
17579 boardp->id);
17580 break;
17581 case ASC_WARN_EEPROM_CHKSUM:
17582 ASC_PRINT1
17583 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
17584 boardp->id);
17585 break;
17586 case ASC_WARN_IRQ_MODIFIED:
17587 ASC_PRINT1
17588 ("AscInitGetConfig: board %d: IRQ modified\n",
17589 boardp->id);
17590 break;
17591 case ASC_WARN_CMD_QNG_CONFLICT:
17592 ASC_PRINT1
17593 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
17594 boardp->id);
17595 break;
17596 default:
17597 ASC_PRINT2
17598 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
17599 boardp->id, ret);
17600 break;
17601 }
17602 if ((err_code = asc_dvc_varp->err_code) != 0) {
17603 ASC_PRINT3
17604 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17605 boardp->id,
17606 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
17607 }
17608 } else {
17609 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
17610 if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
17611 ASC_PRINT2
17612 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
17613 boardp->id, ret);
17614 }
17615 if ((err_code = adv_dvc_varp->err_code) != 0) {
17616 ASC_PRINT2
17617 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
17618 boardp->id, adv_dvc_varp->err_code);
17619 }
17620 }
17621
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017622 if (err_code != 0)
17623 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017624
17625 /*
17626 * Save the EEPROM configuration so that it can be displayed
17627 * from /proc/scsi/advansys/[0...].
17628 */
17629 if (ASC_NARROW_BOARD(boardp)) {
17630
17631 ASCEEP_CONFIG *ep;
17632
17633 /*
17634 * Set the adapter's target id bit in the 'init_tidmask' field.
17635 */
17636 boardp->init_tidmask |=
17637 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
17638
17639 /*
17640 * Save EEPROM settings for the board.
17641 */
17642 ep = &boardp->eep_config.asc_eep;
17643
17644 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
17645 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
17646 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
17647 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
17648 ep->start_motor = asc_dvc_varp->start_motor;
17649 ep->cntl = asc_dvc_varp->dvc_cntl;
17650 ep->no_scam = asc_dvc_varp->no_scam;
17651 ep->max_total_qng = asc_dvc_varp->max_total_qng;
17652 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
17653 /* 'max_tag_qng' is set to the same value for every device. */
17654 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
17655 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
17656 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
17657 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
17658 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
17659 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
17660 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
17661
17662 /*
17663 * Modify board configuration.
17664 */
17665 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
17666 switch (ret = AscInitSetConfig(asc_dvc_varp)) {
17667 case 0: /* No error. */
17668 break;
17669 case ASC_WARN_IO_PORT_ROTATE:
17670 ASC_PRINT1
17671 ("AscInitSetConfig: board %d: I/O port address modified\n",
17672 boardp->id);
17673 break;
17674 case ASC_WARN_AUTO_CONFIG:
17675 ASC_PRINT1
17676 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
17677 boardp->id);
17678 break;
17679 case ASC_WARN_EEPROM_CHKSUM:
17680 ASC_PRINT1
17681 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
17682 boardp->id);
17683 break;
17684 case ASC_WARN_IRQ_MODIFIED:
17685 ASC_PRINT1
17686 ("AscInitSetConfig: board %d: IRQ modified\n",
17687 boardp->id);
17688 break;
17689 case ASC_WARN_CMD_QNG_CONFLICT:
17690 ASC_PRINT1
17691 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
17692 boardp->id);
17693 break;
17694 default:
17695 ASC_PRINT2
17696 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
17697 boardp->id, ret);
17698 break;
17699 }
17700 if (asc_dvc_varp->err_code != 0) {
17701 ASC_PRINT3
17702 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17703 boardp->id,
17704 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017705 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017706 }
17707
17708 /*
17709 * Finish initializing the 'Scsi_Host' structure.
17710 */
17711 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
17712 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
17713 shost->irq = asc_dvc_varp->irq_no;
17714 }
17715 } else {
17716 ADVEEP_3550_CONFIG *ep_3550;
17717 ADVEEP_38C0800_CONFIG *ep_38C0800;
17718 ADVEEP_38C1600_CONFIG *ep_38C1600;
17719
17720 /*
17721 * Save Wide EEP Configuration Information.
17722 */
17723 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17724 ep_3550 = &boardp->eep_config.adv_3550_eep;
17725
17726 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
17727 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
17728 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17729 ep_3550->termination = adv_dvc_varp->cfg->termination;
17730 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
17731 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
17732 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
17733 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
17734 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
17735 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
17736 ep_3550->start_motor = adv_dvc_varp->start_motor;
17737 ep_3550->scsi_reset_delay =
17738 adv_dvc_varp->scsi_reset_wait;
17739 ep_3550->serial_number_word1 =
17740 adv_dvc_varp->cfg->serial1;
17741 ep_3550->serial_number_word2 =
17742 adv_dvc_varp->cfg->serial2;
17743 ep_3550->serial_number_word3 =
17744 adv_dvc_varp->cfg->serial3;
17745 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17746 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
17747
17748 ep_38C0800->adapter_scsi_id =
17749 adv_dvc_varp->chip_scsi_id;
17750 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
17751 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17752 ep_38C0800->termination_lvd =
17753 adv_dvc_varp->cfg->termination;
17754 ep_38C0800->disc_enable =
17755 adv_dvc_varp->cfg->disc_enable;
17756 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
17757 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
17758 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17759 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17760 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17761 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17762 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17763 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17764 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
17765 ep_38C0800->scsi_reset_delay =
17766 adv_dvc_varp->scsi_reset_wait;
17767 ep_38C0800->serial_number_word1 =
17768 adv_dvc_varp->cfg->serial1;
17769 ep_38C0800->serial_number_word2 =
17770 adv_dvc_varp->cfg->serial2;
17771 ep_38C0800->serial_number_word3 =
17772 adv_dvc_varp->cfg->serial3;
17773 } else {
17774 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
17775
17776 ep_38C1600->adapter_scsi_id =
17777 adv_dvc_varp->chip_scsi_id;
17778 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
17779 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17780 ep_38C1600->termination_lvd =
17781 adv_dvc_varp->cfg->termination;
17782 ep_38C1600->disc_enable =
17783 adv_dvc_varp->cfg->disc_enable;
17784 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
17785 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
17786 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17787 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17788 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17789 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17790 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17791 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17792 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
17793 ep_38C1600->scsi_reset_delay =
17794 adv_dvc_varp->scsi_reset_wait;
17795 ep_38C1600->serial_number_word1 =
17796 adv_dvc_varp->cfg->serial1;
17797 ep_38C1600->serial_number_word2 =
17798 adv_dvc_varp->cfg->serial2;
17799 ep_38C1600->serial_number_word3 =
17800 adv_dvc_varp->cfg->serial3;
17801 }
17802
17803 /*
17804 * Set the adapter's target id bit in the 'init_tidmask' field.
17805 */
17806 boardp->init_tidmask |=
17807 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
17808
17809 /*
17810 * Finish initializing the 'Scsi_Host' structure.
17811 */
17812 shost->irq = adv_dvc_varp->irq_no;
17813 }
17814
17815 /*
17816 * Channels are numbered beginning with 0. For AdvanSys one host
17817 * structure supports one channel. Multi-channel boards have a
17818 * separate host structure for each channel.
17819 */
17820 shost->max_channel = 0;
17821 if (ASC_NARROW_BOARD(boardp)) {
17822 shost->max_id = ASC_MAX_TID + 1;
17823 shost->max_lun = ASC_MAX_LUN + 1;
17824
17825 shost->io_port = asc_dvc_varp->iop_base;
17826 boardp->asc_n_io_port = ASC_IOADR_GAP;
17827 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
17828
17829 /* Set maximum number of queues the adapter can handle. */
17830 shost->can_queue = asc_dvc_varp->max_total_qng;
17831 } else {
17832 shost->max_id = ADV_MAX_TID + 1;
17833 shost->max_lun = ADV_MAX_LUN + 1;
17834
17835 /*
17836 * Save the I/O Port address and length even though
17837 * I/O ports are not used to access Wide boards.
17838 * Instead the Wide boards are accessed with
17839 * PCI Memory Mapped I/O.
17840 */
17841 shost->io_port = iop;
17842 boardp->asc_n_io_port = iolen;
17843
17844 shost->this_id = adv_dvc_varp->chip_scsi_id;
17845
17846 /* Set maximum number of queues the adapter can handle. */
17847 shost->can_queue = adv_dvc_varp->max_host_qng;
17848 }
17849
17850 /*
17851 * 'n_io_port' currently is one byte.
17852 *
17853 * Set a value to 'n_io_port', but never referenced it because
17854 * it may be truncated.
17855 */
17856 shost->n_io_port = boardp->asc_n_io_port <= 255 ?
17857 boardp->asc_n_io_port : 255;
17858
17859 /*
17860 * Following v1.3.89, 'cmd_per_lun' is no longer needed
17861 * and should be set to zero.
17862 *
17863 * But because of a bug introduced in v1.3.89 if the driver is
17864 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
17865 * SCSI function 'allocate_device' will panic. To allow the driver
17866 * to work as a module in these kernels set 'cmd_per_lun' to 1.
17867 *
17868 * Note: This is wrong. cmd_per_lun should be set to the depth
17869 * you want on untagged devices always.
17870 #ifdef MODULE
17871 */
17872 shost->cmd_per_lun = 1;
17873/* #else
17874 shost->cmd_per_lun = 0;
17875#endif */
17876
17877 /*
17878 * Set the maximum number of scatter-gather elements the
17879 * adapter can handle.
17880 */
17881 if (ASC_NARROW_BOARD(boardp)) {
17882 /*
17883 * Allow two commands with 'sg_tablesize' scatter-gather
17884 * elements to be executed simultaneously. This value is
17885 * the theoretical hardware limit. It may be decreased
17886 * below.
17887 */
17888 shost->sg_tablesize =
17889 (((asc_dvc_varp->max_total_qng - 2) / 2) *
17890 ASC_SG_LIST_PER_Q) + 1;
17891 } else {
17892 shost->sg_tablesize = ADV_MAX_SG_LIST;
17893 }
17894
17895 /*
17896 * The value of 'sg_tablesize' can not exceed the SCSI
17897 * mid-level driver definition of SG_ALL. SG_ALL also
17898 * must not be exceeded, because it is used to define the
17899 * size of the scatter-gather table in 'struct asc_sg_head'.
17900 */
17901 if (shost->sg_tablesize > SG_ALL) {
17902 shost->sg_tablesize = SG_ALL;
17903 }
17904
17905 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
17906
17907 /* BIOS start address. */
17908 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017909 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
17910 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017911 } else {
17912 /*
17913 * Fill-in BIOS board variables. The Wide BIOS saves
17914 * information in LRAM that is used by the driver.
17915 */
17916 AdvReadWordLram(adv_dvc_varp->iop_base,
17917 BIOS_SIGNATURE, boardp->bios_signature);
17918 AdvReadWordLram(adv_dvc_varp->iop_base,
17919 BIOS_VERSION, boardp->bios_version);
17920 AdvReadWordLram(adv_dvc_varp->iop_base,
17921 BIOS_CODESEG, boardp->bios_codeseg);
17922 AdvReadWordLram(adv_dvc_varp->iop_base,
17923 BIOS_CODELEN, boardp->bios_codelen);
17924
17925 ASC_DBG2(1,
17926 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
17927 boardp->bios_signature, boardp->bios_version);
17928
17929 ASC_DBG2(1,
17930 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
17931 boardp->bios_codeseg, boardp->bios_codelen);
17932
17933 /*
17934 * If the BIOS saved a valid signature, then fill in
17935 * the BIOS code segment base address.
17936 */
17937 if (boardp->bios_signature == 0x55AA) {
17938 /*
17939 * Convert x86 realmode code segment to a linear
17940 * address by shifting left 4.
17941 */
17942 shost->base = ((ulong)boardp->bios_codeseg << 4);
17943 } else {
17944 shost->base = 0;
17945 }
17946 }
17947
17948 /*
17949 * Register Board Resources - I/O Port, DMA, IRQ
17950 */
17951
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017952 /* Register DMA Channel for Narrow boards. */
17953 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
17954#ifdef CONFIG_ISA
17955 if (ASC_NARROW_BOARD(boardp)) {
17956 /* Register DMA channel for ISA bus. */
17957 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
17958 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017959 ret = request_dma(shost->dma_channel, "advansys");
17960 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017961 ASC_PRINT3
17962 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
17963 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017964 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017965 }
17966 AscEnableIsaDma(shost->dma_channel);
17967 }
17968 }
17969#endif /* CONFIG_ISA */
17970
17971 /* Register IRQ Number. */
17972 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017973
17974 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
17975 "advansys", shost);
17976
17977 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017978 if (ret == -EBUSY) {
17979 ASC_PRINT2
17980 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
17981 boardp->id, shost->irq);
17982 } else if (ret == -EINVAL) {
17983 ASC_PRINT2
17984 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
17985 boardp->id, shost->irq);
17986 } else {
17987 ASC_PRINT3
17988 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
17989 boardp->id, shost->irq, ret);
17990 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017991 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017992 }
17993
17994 /*
17995 * Initialize board RISC chip and enable interrupts.
17996 */
17997 if (ASC_NARROW_BOARD(boardp)) {
17998 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
17999 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
18000 err_code = asc_dvc_varp->err_code;
18001
18002 if (warn_code || err_code) {
18003 ASC_PRINT4
18004 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
18005 boardp->id,
18006 asc_dvc_varp->init_state, warn_code, err_code);
18007 }
18008 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018009 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018010 }
18011
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018012 if (err_code != 0)
18013 goto err_free_wide_mem;
18014
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018015 ASC_DBG_PRT_SCSI_HOST(2, shost);
18016
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018017 ret = scsi_add_host(shost, dev);
18018 if (ret)
18019 goto err_free_wide_mem;
18020
18021 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018022 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018023
18024 err_free_wide_mem:
18025 advansys_wide_free_mem(boardp);
18026 free_irq(shost->irq, shost);
18027 err_free_dma:
18028 if (shost->dma_channel != NO_ISA_DMA)
18029 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018030 err_free_proc:
18031 kfree(boardp->prtbuf);
18032 err_unmap:
18033 if (boardp->ioremap_addr)
18034 iounmap(boardp->ioremap_addr);
18035 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018036 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018037 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018038}
18039
18040/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018041 * advansys_release()
18042 *
18043 * Release resources allocated for a single AdvanSys adapter.
18044 */
18045static int advansys_release(struct Scsi_Host *shost)
18046{
18047 asc_board_t *boardp;
18048
18049 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018050 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018051 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060018052 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018053 if (shost->dma_channel != NO_ISA_DMA) {
18054 ASC_DBG(1, "advansys_release: free_dma()\n");
18055 free_dma(shost->dma_channel);
18056 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018057 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018058 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018059 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018060 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018061 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018062 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018063 ASC_DBG(1, "advansys_release: end\n");
18064 return 0;
18065}
18066
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018067static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
18068 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
18069 0x0210, 0x0230, 0x0250, 0x0330
18070};
18071
18072static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
18073{
18074 PortAddr iop_base = _asc_def_iop_base[id];
18075 struct Scsi_Host *shost;
18076
18077 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060018078 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
18079 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018080 return -ENODEV;
18081 }
18082 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018083 if (!AscFindSignature(iop_base))
18084 goto nodev;
18085 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
18086 goto nodev;
18087
18088 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018089 if (!shost)
18090 goto nodev;
18091
18092 dev_set_drvdata(dev, shost);
18093 return 0;
18094
18095 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060018096 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018097 return -ENODEV;
18098}
18099
18100static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
18101{
Matthew Wilcox71f36112007-07-30 08:04:53 -060018102 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018103 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060018104 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018105 return 0;
18106}
18107
18108static struct isa_driver advansys_isa_driver = {
18109 .probe = advansys_isa_probe,
18110 .remove = __devexit_p(advansys_isa_remove),
18111 .driver = {
18112 .owner = THIS_MODULE,
18113 .name = "advansys",
18114 },
18115};
18116
18117static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
18118{
18119 PortAddr iop_base = _asc_def_iop_base[id];
18120 struct Scsi_Host *shost;
18121
18122 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060018123 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
18124 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018125 return -ENODEV;
18126 }
18127 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018128 if (!AscFindSignature(iop_base))
18129 goto nodev;
18130 /*
18131 * I don't think this condition can actually happen, but the old
18132 * driver did it, and the chances of finding a VLB setup in 2007
18133 * to do testing with is slight to none.
18134 */
18135 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
18136 goto nodev;
18137
18138 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018139 if (!shost)
18140 goto nodev;
18141
18142 dev_set_drvdata(dev, shost);
18143 return 0;
18144
18145 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060018146 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018147 return -ENODEV;
18148}
18149
18150static struct isa_driver advansys_vlb_driver = {
18151 .probe = advansys_vlb_probe,
18152 .remove = __devexit_p(advansys_isa_remove),
18153 .driver = {
18154 .owner = THIS_MODULE,
18155 .name = "advansys",
18156 },
18157};
18158
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018159static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
18160 { "ABP7401" },
18161 { "ABP7501" },
18162 { "" }
18163};
18164
18165MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
18166
18167/*
18168 * EISA is a little more tricky than PCI; each EISA device may have two
18169 * channels, and this driver is written to make each channel its own Scsi_Host
18170 */
18171struct eisa_scsi_data {
18172 struct Scsi_Host *host[2];
18173};
18174
18175static int __devinit advansys_eisa_probe(struct device *dev)
18176{
18177 int i, ioport;
18178 int err;
18179 struct eisa_device *edev = to_eisa_device(dev);
18180 struct eisa_scsi_data *data;
18181
18182 err = -ENOMEM;
18183 data = kzalloc(sizeof(*data), GFP_KERNEL);
18184 if (!data)
18185 goto fail;
18186 ioport = edev->base_addr + 0xc30;
18187
18188 err = -ENODEV;
18189 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060018190 if (!request_region(ioport, ASC_IOADR_GAP, "advansys")) {
18191 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
18192 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018193 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018194 }
18195 if (!AscFindSignature(ioport)) {
18196 release_region(ioport, ASC_IOADR_GAP);
18197 continue;
18198 }
18199
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018200 /*
18201 * I don't know why we need to do this for EISA chips, but
18202 * not for any others. It looks to be equivalent to
18203 * AscGetChipCfgMsw, but I may have overlooked something,
18204 * so I'm not converting it until I get an EISA board to
18205 * test with.
18206 */
18207 inw(ioport + 4);
18208 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f36112007-07-30 08:04:53 -060018209 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018210 err = 0;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018211 } else {
18212 release_region(ioport, ASC_IOADR_GAP);
18213 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018214 }
18215
18216 if (err) {
18217 kfree(data);
18218 } else {
18219 dev_set_drvdata(dev, data);
18220 }
18221
18222 fail:
18223 return err;
18224}
18225
18226static __devexit int advansys_eisa_remove(struct device *dev)
18227{
18228 int i;
18229 struct eisa_scsi_data *data = dev_get_drvdata(dev);
18230
18231 for (i = 0; i < 2; i++) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060018232 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018233 struct Scsi_Host *shost = data->host[i];
18234 if (!shost)
18235 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018236 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018237 advansys_release(shost);
Matthew Wilcox71f36112007-07-30 08:04:53 -060018238 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018239 }
18240
18241 kfree(data);
18242 return 0;
18243}
18244
18245static struct eisa_driver advansys_eisa_driver = {
18246 .id_table = advansys_eisa_table,
18247 .driver = {
18248 .name = "advansys",
18249 .probe = advansys_eisa_probe,
18250 .remove = __devexit_p(advansys_eisa_remove),
18251 }
18252};
18253
Dave Jones2672ea82006-08-02 17:11:49 -040018254/* PCI Devices supported by this driver */
18255static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018256 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
18257 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18258 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
18259 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18260 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
18261 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18262 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
18263 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18264 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
18265 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18266 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
18267 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18268 {}
Dave Jones2672ea82006-08-02 17:11:49 -040018269};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018270
Dave Jones2672ea82006-08-02 17:11:49 -040018271MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018272
Matthew Wilcox9649af32007-07-26 21:51:47 -060018273static void __devinit advansys_set_latency(struct pci_dev *pdev)
18274{
18275 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
18276 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
18277 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
18278 } else {
18279 u8 latency;
18280 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
18281 if (latency < 0x20)
18282 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
18283 }
18284}
18285
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018286static int __devinit
18287advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
18288{
18289 int err, ioport;
18290 struct Scsi_Host *shost;
18291
18292 err = pci_enable_device(pdev);
18293 if (err)
18294 goto fail;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018295 err = pci_request_regions(pdev, "advansys");
18296 if (err)
18297 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060018298 pci_set_master(pdev);
18299 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018300
18301 if (pci_resource_len(pdev, 0) == 0)
18302 goto nodev;
18303
18304 ioport = pci_resource_start(pdev, 0);
18305 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
18306
18307 if (!shost)
18308 goto nodev;
18309
18310 pci_set_drvdata(pdev, shost);
18311 return 0;
18312
18313 nodev:
18314 err = -ENODEV;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018315 pci_release_regions(pdev);
18316 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018317 pci_disable_device(pdev);
18318 fail:
18319 return err;
18320}
18321
18322static void __devexit advansys_pci_remove(struct pci_dev *pdev)
18323{
18324 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060018325 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018326 pci_disable_device(pdev);
18327}
18328
18329static struct pci_driver advansys_pci_driver = {
18330 .name = "advansys",
18331 .id_table = advansys_pci_tbl,
18332 .probe = advansys_pci_probe,
18333 .remove = __devexit_p(advansys_pci_remove),
18334};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018335
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018336static int __init advansys_init(void)
18337{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018338 int error;
18339
18340 error = isa_register_driver(&advansys_isa_driver,
18341 ASC_IOADR_TABLE_MAX_IX);
18342 if (error)
18343 goto fail;
18344
18345 error = isa_register_driver(&advansys_vlb_driver,
18346 ASC_IOADR_TABLE_MAX_IX);
18347 if (error)
18348 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018349
18350 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018351 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018352 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018353
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018354 error = pci_register_driver(&advansys_pci_driver);
18355 if (error)
18356 goto unregister_eisa;
18357
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018358 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018359
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018360 unregister_eisa:
18361 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018362 unregister_vlb:
18363 isa_unregister_driver(&advansys_vlb_driver);
18364 unregister_isa:
18365 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018366 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018367 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018368}
18369
18370static void __exit advansys_exit(void)
18371{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018372 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018373 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018374 isa_unregister_driver(&advansys_vlb_driver);
18375 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018376}
18377
18378module_init(advansys_init);
18379module_exit(advansys_exit);
18380
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018381MODULE_LICENSE("GPL");