blob: 424549d79b13582b5f693168e9c333e799f1a6a0 [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 *);
1914static int AscCompareString(uchar *, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001916static ushort AscGetEisaChipCfg(PortAddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001918static uchar AscGetChipScsiCtrl(PortAddr);
1919static uchar AscSetChipScsiID(PortAddr, uchar);
1920static uchar AscGetChipVersion(PortAddr, ushort);
1921static ushort AscGetChipBusType(PortAddr);
1922static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
1923static int AscFindSignature(PortAddr);
1924static void AscToggleIRQAct(PortAddr);
1925static uchar AscGetChipIRQ(PortAddr, ushort);
1926static uchar AscSetChipIRQ(PortAddr, uchar, ushort);
1927static ushort AscGetChipBiosAddress(PortAddr, ushort);
1928static inline ulong DvcEnterCritical(void);
1929static inline void DvcLeaveCritical(ulong);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001930static ushort AscGetChipBiosAddress(PortAddr, ushort);
1931static void DvcSleepMilliSecond(ASC_DCNT);
1932static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
1933static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
1934static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001935static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
1936static void AscAsyncFix(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
1937static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
1938static void AscInquiryHandling(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
1939static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
1940static int AscISR(ASC_DVC_VAR *);
1941static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
1942static int AscSgListToQueue(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001944static void AscEnableIsaDma(uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001946static ASC_DCNT AscGetMaxDmaCount(ushort);
1947static const char *advansys_info(struct Scsi_Host *shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948
1949/*
1950 * --- Adv Library Constants and Macros
1951 */
1952
1953#define ADV_LIB_VERSION_MAJOR 5
1954#define ADV_LIB_VERSION_MINOR 14
1955
1956/*
1957 * Define Adv Library required special types.
1958 */
1959
1960/*
1961 * Portable Data Types
1962 *
1963 * Any instance where a 32-bit long or pointer type is assumed
1964 * for precision or HW defined structures, the following define
1965 * types must be used. In Linux the char, short, and int types
1966 * are all consistent at 8, 16, and 32 bits respectively. Pointers
1967 * and long types are 64 bits on Alpha and UltraSPARC.
1968 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001969#define ADV_PADDR __u32 /* Physical address data type. */
1970#define ADV_VADDR __u32 /* Virtual address data type. */
1971#define ADV_DCNT __u32 /* Unsigned Data count type. */
1972#define ADV_SDCNT __s32 /* Signed Data count type. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
1974/*
1975 * These macros are used to convert a virtual address to a
1976 * 32-bit value. This currently can be used on Linux Alpha
1977 * which uses 64-bit virtual address but a 32-bit bus address.
1978 * This is likely to break in the future, but doing this now
1979 * will give us time to change the HW and FW to handle 64-bit
1980 * addresses.
1981 */
1982#define ADV_VADDR_TO_U32 virt_to_bus
1983#define ADV_U32_TO_VADDR bus_to_virt
1984
Matthew Wilcox27c868c2007-07-26 10:56:23 -04001985#define AdvPortAddr void __iomem * /* Virtual memory address size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986
1987/*
1988 * Define Adv Library required memory access macros.
1989 */
1990#define ADV_MEM_READB(addr) readb(addr)
1991#define ADV_MEM_READW(addr) readw(addr)
1992#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
1993#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
1994#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
1995
1996#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
1997
1998/*
1999 * For wide boards a CDB length maximum of 16 bytes
2000 * is supported.
2001 */
2002#define ADV_MAX_CDB_LEN 16
2003
2004/*
2005 * Define total number of simultaneous maximum element scatter-gather
2006 * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
2007 * maximum number of outstanding commands per wide host adapter. Each
2008 * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
2009 * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
2010 * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
2011 * structures or 255 scatter-gather elements.
2012 *
2013 */
2014#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG
2015
2016/*
2017 * Define Adv Library required maximum number of scatter-gather
2018 * elements per request.
2019 */
2020#define ADV_MAX_SG_LIST 255
2021
2022/* Number of SG blocks needed. */
2023#define ADV_NUM_SG_BLOCK \
2024 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
2025
2026/* Total contiguous memory needed for SG blocks. */
2027#define ADV_SG_TOTAL_MEM_SIZE \
2028 (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
2029
2030#define ADV_PAGE_SIZE PAGE_SIZE
2031
2032#define ADV_NUM_PAGE_CROSSING \
2033 ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2034
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035#define ADV_EEP_DVC_CFG_BEGIN (0x00)
2036#define ADV_EEP_DVC_CFG_END (0x15)
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002037#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038#define ADV_EEP_MAX_WORD_ADDR (0x1E)
2039
2040#define ADV_EEP_DELAY_MS 100
2041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002042#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
2043#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044/*
2045 * For the ASC3550 Bit 13 is Termination Polarity control bit.
2046 * For later ICs Bit 13 controls whether the CIS (Card Information
2047 * Service Section) is loaded from EEPROM.
2048 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002049#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
2050#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051/*
2052 * ASC38C1600 Bit 11
2053 *
2054 * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
2055 * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
2056 * Function 0 will specify INT B.
2057 *
2058 * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
2059 * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
2060 * Function 1 will specify INT A.
2061 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002062#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002064typedef struct adveep_3550_config {
2065 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002067 ushort cfg_lsw; /* 00 power up initialization */
2068 /* bit 13 set - Term Polarity Control */
2069 /* bit 14 set - BIOS Enable */
2070 /* bit 15 set - Big Endian Mode */
2071 ushort cfg_msw; /* 01 unused */
2072 ushort disc_enable; /* 02 disconnect enable */
2073 ushort wdtr_able; /* 03 Wide DTR able */
2074 ushort sdtr_able; /* 04 Synchronous DTR able */
2075 ushort start_motor; /* 05 send start up motor */
2076 ushort tagqng_able; /* 06 tag queuing able */
2077 ushort bios_scan; /* 07 BIOS device control */
2078 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002080 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2081 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002083 uchar scsi_reset_delay; /* 10 reset delay */
2084 uchar bios_id_lun; /* first boot device scsi id & lun */
2085 /* high nibble is lun */
2086 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002088 uchar termination; /* 11 0 - automatic */
2089 /* 1 - low off / high off */
2090 /* 2 - low off / high on */
2091 /* 3 - low on / high on */
2092 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002094 uchar reserved1; /* reserved byte (not used) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002096 ushort bios_ctrl; /* 12 BIOS control bits */
2097 /* bit 0 BIOS don't act as initiator. */
2098 /* bit 1 BIOS > 1 GB support */
2099 /* bit 2 BIOS > 2 Disk Support */
2100 /* bit 3 BIOS don't support removables */
2101 /* bit 4 BIOS support bootable CD */
2102 /* bit 5 BIOS scan enabled */
2103 /* bit 6 BIOS support multiple LUNs */
2104 /* bit 7 BIOS display of message */
2105 /* bit 8 SCAM disabled */
2106 /* bit 9 Reset SCSI bus during init. */
2107 /* bit 10 */
2108 /* bit 11 No verbose initialization. */
2109 /* bit 12 SCSI parity enabled */
2110 /* bit 13 */
2111 /* bit 14 */
2112 /* bit 15 */
2113 ushort ultra_able; /* 13 ULTRA speed able */
2114 ushort reserved2; /* 14 reserved */
2115 uchar max_host_qng; /* 15 maximum host queuing */
2116 uchar max_dvc_qng; /* maximum per device queuing */
2117 ushort dvc_cntl; /* 16 control bit for driver */
2118 ushort bug_fix; /* 17 control bit for bug fix */
2119 ushort serial_number_word1; /* 18 Board serial number word 1 */
2120 ushort serial_number_word2; /* 19 Board serial number word 2 */
2121 ushort serial_number_word3; /* 20 Board serial number word 3 */
2122 ushort check_sum; /* 21 EEP check sum */
2123 uchar oem_name[16]; /* 22 OEM name */
2124 ushort dvc_err_code; /* 30 last device driver error code */
2125 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2126 ushort adv_err_addr; /* 32 last uc error address */
2127 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2128 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2129 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2130 ushort num_of_err; /* 36 number of error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131} ADVEEP_3550_CONFIG;
2132
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002133typedef struct adveep_38C0800_config {
2134 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002136 ushort cfg_lsw; /* 00 power up initialization */
2137 /* bit 13 set - Load CIS */
2138 /* bit 14 set - BIOS Enable */
2139 /* bit 15 set - Big Endian Mode */
2140 ushort cfg_msw; /* 01 unused */
2141 ushort disc_enable; /* 02 disconnect enable */
2142 ushort wdtr_able; /* 03 Wide DTR able */
2143 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2144 ushort start_motor; /* 05 send start up motor */
2145 ushort tagqng_able; /* 06 tag queuing able */
2146 ushort bios_scan; /* 07 BIOS device control */
2147 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002149 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2150 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002152 uchar scsi_reset_delay; /* 10 reset delay */
2153 uchar bios_id_lun; /* first boot device scsi id & lun */
2154 /* high nibble is lun */
2155 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002157 uchar termination_se; /* 11 0 - automatic */
2158 /* 1 - low off / high off */
2159 /* 2 - low off / high on */
2160 /* 3 - low on / high on */
2161 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002163 uchar termination_lvd; /* 11 0 - automatic */
2164 /* 1 - low off / high off */
2165 /* 2 - low off / high on */
2166 /* 3 - low on / high on */
2167 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002169 ushort bios_ctrl; /* 12 BIOS control bits */
2170 /* bit 0 BIOS don't act as initiator. */
2171 /* bit 1 BIOS > 1 GB support */
2172 /* bit 2 BIOS > 2 Disk Support */
2173 /* bit 3 BIOS don't support removables */
2174 /* bit 4 BIOS support bootable CD */
2175 /* bit 5 BIOS scan enabled */
2176 /* bit 6 BIOS support multiple LUNs */
2177 /* bit 7 BIOS display of message */
2178 /* bit 8 SCAM disabled */
2179 /* bit 9 Reset SCSI bus during init. */
2180 /* bit 10 */
2181 /* bit 11 No verbose initialization. */
2182 /* bit 12 SCSI parity enabled */
2183 /* bit 13 */
2184 /* bit 14 */
2185 /* bit 15 */
2186 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2187 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2188 uchar max_host_qng; /* 15 maximum host queueing */
2189 uchar max_dvc_qng; /* maximum per device queuing */
2190 ushort dvc_cntl; /* 16 control bit for driver */
2191 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2192 ushort serial_number_word1; /* 18 Board serial number word 1 */
2193 ushort serial_number_word2; /* 19 Board serial number word 2 */
2194 ushort serial_number_word3; /* 20 Board serial number word 3 */
2195 ushort check_sum; /* 21 EEP check sum */
2196 uchar oem_name[16]; /* 22 OEM name */
2197 ushort dvc_err_code; /* 30 last device driver error code */
2198 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2199 ushort adv_err_addr; /* 32 last uc error address */
2200 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2201 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2202 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2203 ushort reserved36; /* 36 reserved */
2204 ushort reserved37; /* 37 reserved */
2205 ushort reserved38; /* 38 reserved */
2206 ushort reserved39; /* 39 reserved */
2207 ushort reserved40; /* 40 reserved */
2208 ushort reserved41; /* 41 reserved */
2209 ushort reserved42; /* 42 reserved */
2210 ushort reserved43; /* 43 reserved */
2211 ushort reserved44; /* 44 reserved */
2212 ushort reserved45; /* 45 reserved */
2213 ushort reserved46; /* 46 reserved */
2214 ushort reserved47; /* 47 reserved */
2215 ushort reserved48; /* 48 reserved */
2216 ushort reserved49; /* 49 reserved */
2217 ushort reserved50; /* 50 reserved */
2218 ushort reserved51; /* 51 reserved */
2219 ushort reserved52; /* 52 reserved */
2220 ushort reserved53; /* 53 reserved */
2221 ushort reserved54; /* 54 reserved */
2222 ushort reserved55; /* 55 reserved */
2223 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2224 ushort cisprt_msw; /* 57 CIS PTR MSW */
2225 ushort subsysvid; /* 58 SubSystem Vendor ID */
2226 ushort subsysid; /* 59 SubSystem ID */
2227 ushort reserved60; /* 60 reserved */
2228 ushort reserved61; /* 61 reserved */
2229 ushort reserved62; /* 62 reserved */
2230 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231} ADVEEP_38C0800_CONFIG;
2232
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002233typedef struct adveep_38C1600_config {
2234 /* Word Offset, Description */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002236 ushort cfg_lsw; /* 00 power up initialization */
2237 /* bit 11 set - Func. 0 INTB, Func. 1 INTA */
2238 /* clear - Func. 0 INTA, Func. 1 INTB */
2239 /* bit 13 set - Load CIS */
2240 /* bit 14 set - BIOS Enable */
2241 /* bit 15 set - Big Endian Mode */
2242 ushort cfg_msw; /* 01 unused */
2243 ushort disc_enable; /* 02 disconnect enable */
2244 ushort wdtr_able; /* 03 Wide DTR able */
2245 ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */
2246 ushort start_motor; /* 05 send start up motor */
2247 ushort tagqng_able; /* 06 tag queuing able */
2248 ushort bios_scan; /* 07 BIOS device control */
2249 ushort scam_tolerant; /* 08 no scam */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002251 uchar adapter_scsi_id; /* 09 Host Adapter ID */
2252 uchar bios_boot_delay; /* power up wait */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002254 uchar scsi_reset_delay; /* 10 reset delay */
2255 uchar bios_id_lun; /* first boot device scsi id & lun */
2256 /* high nibble is lun */
2257 /* low nibble is scsi id */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002259 uchar termination_se; /* 11 0 - automatic */
2260 /* 1 - low off / high off */
2261 /* 2 - low off / high on */
2262 /* 3 - low on / high on */
2263 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002265 uchar termination_lvd; /* 11 0 - automatic */
2266 /* 1 - low off / high off */
2267 /* 2 - low off / high on */
2268 /* 3 - low on / high on */
2269 /* There is no low on / high off */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002271 ushort bios_ctrl; /* 12 BIOS control bits */
2272 /* bit 0 BIOS don't act as initiator. */
2273 /* bit 1 BIOS > 1 GB support */
2274 /* bit 2 BIOS > 2 Disk Support */
2275 /* bit 3 BIOS don't support removables */
2276 /* bit 4 BIOS support bootable CD */
2277 /* bit 5 BIOS scan enabled */
2278 /* bit 6 BIOS support multiple LUNs */
2279 /* bit 7 BIOS display of message */
2280 /* bit 8 SCAM disabled */
2281 /* bit 9 Reset SCSI bus during init. */
2282 /* bit 10 Basic Integrity Checking disabled */
2283 /* bit 11 No verbose initialization. */
2284 /* bit 12 SCSI parity enabled */
2285 /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
2286 /* bit 14 */
2287 /* bit 15 */
2288 ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */
2289 ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */
2290 uchar max_host_qng; /* 15 maximum host queueing */
2291 uchar max_dvc_qng; /* maximum per device queuing */
2292 ushort dvc_cntl; /* 16 control bit for driver */
2293 ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */
2294 ushort serial_number_word1; /* 18 Board serial number word 1 */
2295 ushort serial_number_word2; /* 19 Board serial number word 2 */
2296 ushort serial_number_word3; /* 20 Board serial number word 3 */
2297 ushort check_sum; /* 21 EEP check sum */
2298 uchar oem_name[16]; /* 22 OEM name */
2299 ushort dvc_err_code; /* 30 last device driver error code */
2300 ushort adv_err_code; /* 31 last uc and Adv Lib error code */
2301 ushort adv_err_addr; /* 32 last uc error address */
2302 ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
2303 ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
2304 ushort saved_adv_err_addr; /* 35 saved last uc error address */
2305 ushort reserved36; /* 36 reserved */
2306 ushort reserved37; /* 37 reserved */
2307 ushort reserved38; /* 38 reserved */
2308 ushort reserved39; /* 39 reserved */
2309 ushort reserved40; /* 40 reserved */
2310 ushort reserved41; /* 41 reserved */
2311 ushort reserved42; /* 42 reserved */
2312 ushort reserved43; /* 43 reserved */
2313 ushort reserved44; /* 44 reserved */
2314 ushort reserved45; /* 45 reserved */
2315 ushort reserved46; /* 46 reserved */
2316 ushort reserved47; /* 47 reserved */
2317 ushort reserved48; /* 48 reserved */
2318 ushort reserved49; /* 49 reserved */
2319 ushort reserved50; /* 50 reserved */
2320 ushort reserved51; /* 51 reserved */
2321 ushort reserved52; /* 52 reserved */
2322 ushort reserved53; /* 53 reserved */
2323 ushort reserved54; /* 54 reserved */
2324 ushort reserved55; /* 55 reserved */
2325 ushort cisptr_lsw; /* 56 CIS PTR LSW */
2326 ushort cisprt_msw; /* 57 CIS PTR MSW */
2327 ushort subsysvid; /* 58 SubSystem Vendor ID */
2328 ushort subsysid; /* 59 SubSystem ID */
2329 ushort reserved60; /* 60 reserved */
2330 ushort reserved61; /* 61 reserved */
2331 ushort reserved62; /* 62 reserved */
2332 ushort reserved63; /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333} ADVEEP_38C1600_CONFIG;
2334
2335/*
2336 * EEPROM Commands
2337 */
2338#define ASC_EEP_CMD_DONE 0x0200
2339#define ASC_EEP_CMD_DONE_ERR 0x0001
2340
2341/* cfg_word */
2342#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
2343
2344/* bios_ctrl */
2345#define BIOS_CTRL_BIOS 0x0001
2346#define BIOS_CTRL_EXTENDED_XLAT 0x0002
2347#define BIOS_CTRL_GT_2_DISK 0x0004
2348#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
2349#define BIOS_CTRL_BOOTABLE_CD 0x0010
2350#define BIOS_CTRL_MULTIPLE_LUN 0x0040
2351#define BIOS_CTRL_DISPLAY_MSG 0x0080
2352#define BIOS_CTRL_NO_SCAM 0x0100
2353#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
2354#define BIOS_CTRL_INIT_VERBOSE 0x0800
2355#define BIOS_CTRL_SCSI_PARITY 0x1000
2356#define BIOS_CTRL_AIPP_DIS 0x2000
2357
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002358#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */
2359#define ADV_3550_IOLEN 0x40 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002361#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2362#define ADV_38C0800_IOLEN 0x100 /* I/O Port Range in bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
2364/*
2365 * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
2366 * a special 16K Adv Library and Microcode version. After the issue is
2367 * resolved, should restore 32K support.
2368 *
2369 * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory *
2370 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002371#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */
2372#define ADV_38C1600_IOLEN 0x100 /* I/O Port Range 256 bytes */
2373#define ADV_38C1600_MEMLEN 0x1000 /* Memory Range 4KB bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
2375/*
2376 * Byte I/O register address from base of 'iop_base'.
2377 */
2378#define IOPB_INTR_STATUS_REG 0x00
2379#define IOPB_CHIP_ID_1 0x01
2380#define IOPB_INTR_ENABLES 0x02
2381#define IOPB_CHIP_TYPE_REV 0x03
2382#define IOPB_RES_ADDR_4 0x04
2383#define IOPB_RES_ADDR_5 0x05
2384#define IOPB_RAM_DATA 0x06
2385#define IOPB_RES_ADDR_7 0x07
2386#define IOPB_FLAG_REG 0x08
2387#define IOPB_RES_ADDR_9 0x09
2388#define IOPB_RISC_CSR 0x0A
2389#define IOPB_RES_ADDR_B 0x0B
2390#define IOPB_RES_ADDR_C 0x0C
2391#define IOPB_RES_ADDR_D 0x0D
2392#define IOPB_SOFT_OVER_WR 0x0E
2393#define IOPB_RES_ADDR_F 0x0F
2394#define IOPB_MEM_CFG 0x10
2395#define IOPB_RES_ADDR_11 0x11
2396#define IOPB_GPIO_DATA 0x12
2397#define IOPB_RES_ADDR_13 0x13
2398#define IOPB_FLASH_PAGE 0x14
2399#define IOPB_RES_ADDR_15 0x15
2400#define IOPB_GPIO_CNTL 0x16
2401#define IOPB_RES_ADDR_17 0x17
2402#define IOPB_FLASH_DATA 0x18
2403#define IOPB_RES_ADDR_19 0x19
2404#define IOPB_RES_ADDR_1A 0x1A
2405#define IOPB_RES_ADDR_1B 0x1B
2406#define IOPB_RES_ADDR_1C 0x1C
2407#define IOPB_RES_ADDR_1D 0x1D
2408#define IOPB_RES_ADDR_1E 0x1E
2409#define IOPB_RES_ADDR_1F 0x1F
2410#define IOPB_DMA_CFG0 0x20
2411#define IOPB_DMA_CFG1 0x21
2412#define IOPB_TICKLE 0x22
2413#define IOPB_DMA_REG_WR 0x23
2414#define IOPB_SDMA_STATUS 0x24
2415#define IOPB_SCSI_BYTE_CNT 0x25
2416#define IOPB_HOST_BYTE_CNT 0x26
2417#define IOPB_BYTE_LEFT_TO_XFER 0x27
2418#define IOPB_BYTE_TO_XFER_0 0x28
2419#define IOPB_BYTE_TO_XFER_1 0x29
2420#define IOPB_BYTE_TO_XFER_2 0x2A
2421#define IOPB_BYTE_TO_XFER_3 0x2B
2422#define IOPB_ACC_GRP 0x2C
2423#define IOPB_RES_ADDR_2D 0x2D
2424#define IOPB_DEV_ID 0x2E
2425#define IOPB_RES_ADDR_2F 0x2F
2426#define IOPB_SCSI_DATA 0x30
2427#define IOPB_RES_ADDR_31 0x31
2428#define IOPB_RES_ADDR_32 0x32
2429#define IOPB_SCSI_DATA_HSHK 0x33
2430#define IOPB_SCSI_CTRL 0x34
2431#define IOPB_RES_ADDR_35 0x35
2432#define IOPB_RES_ADDR_36 0x36
2433#define IOPB_RES_ADDR_37 0x37
2434#define IOPB_RAM_BIST 0x38
2435#define IOPB_PLL_TEST 0x39
2436#define IOPB_PCI_INT_CFG 0x3A
2437#define IOPB_RES_ADDR_3B 0x3B
2438#define IOPB_RFIFO_CNT 0x3C
2439#define IOPB_RES_ADDR_3D 0x3D
2440#define IOPB_RES_ADDR_3E 0x3E
2441#define IOPB_RES_ADDR_3F 0x3F
2442
2443/*
2444 * Word I/O register address from base of 'iop_base'.
2445 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002446#define IOPW_CHIP_ID_0 0x00 /* CID0 */
2447#define IOPW_CTRL_REG 0x02 /* CC */
2448#define IOPW_RAM_ADDR 0x04 /* LA */
2449#define IOPW_RAM_DATA 0x06 /* LD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450#define IOPW_RES_ADDR_08 0x08
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002451#define IOPW_RISC_CSR 0x0A /* CSR */
2452#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
2453#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454#define IOPW_RES_ADDR_10 0x10
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002455#define IOPW_SEL_MASK 0x12 /* SM */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456#define IOPW_RES_ADDR_14 0x14
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002457#define IOPW_FLASH_ADDR 0x16 /* FA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458#define IOPW_RES_ADDR_18 0x18
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002459#define IOPW_EE_CMD 0x1A /* EC */
2460#define IOPW_EE_DATA 0x1C /* ED */
2461#define IOPW_SFIFO_CNT 0x1E /* SFC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462#define IOPW_RES_ADDR_20 0x20
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002463#define IOPW_Q_BASE 0x22 /* QB */
2464#define IOPW_QP 0x24 /* QP */
2465#define IOPW_IX 0x26 /* IX */
2466#define IOPW_SP 0x28 /* SP */
2467#define IOPW_PC 0x2A /* PC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468#define IOPW_RES_ADDR_2C 0x2C
2469#define IOPW_RES_ADDR_2E 0x2E
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002470#define IOPW_SCSI_DATA 0x30 /* SD */
2471#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
2472#define IOPW_SCSI_CTRL 0x34 /* SC */
2473#define IOPW_HSHK_CFG 0x36 /* HCFG */
2474#define IOPW_SXFR_STATUS 0x36 /* SXS */
2475#define IOPW_SXFR_CNTL 0x38 /* SXL */
2476#define IOPW_SXFR_CNTH 0x3A /* SXH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477#define IOPW_RES_ADDR_3C 0x3C
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002478#define IOPW_RFIFO_DATA 0x3E /* RFD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
2480/*
2481 * Doubleword I/O register address from base of 'iop_base'.
2482 */
2483#define IOPDW_RES_ADDR_0 0x00
2484#define IOPDW_RAM_DATA 0x04
2485#define IOPDW_RES_ADDR_8 0x08
2486#define IOPDW_RES_ADDR_C 0x0C
2487#define IOPDW_RES_ADDR_10 0x10
2488#define IOPDW_COMMA 0x14
2489#define IOPDW_COMMB 0x18
2490#define IOPDW_RES_ADDR_1C 0x1C
2491#define IOPDW_SDMA_ADDR0 0x20
2492#define IOPDW_SDMA_ADDR1 0x24
2493#define IOPDW_SDMA_COUNT 0x28
2494#define IOPDW_SDMA_ERROR 0x2C
2495#define IOPDW_RDMA_ADDR0 0x30
2496#define IOPDW_RDMA_ADDR1 0x34
2497#define IOPDW_RDMA_COUNT 0x38
2498#define IOPDW_RDMA_ERROR 0x3C
2499
2500#define ADV_CHIP_ID_BYTE 0x25
2501#define ADV_CHIP_ID_WORD 0x04C1
2502
2503#define ADV_SC_SCSI_BUS_RESET 0x2000
2504
2505#define ADV_INTR_ENABLE_HOST_INTR 0x01
2506#define ADV_INTR_ENABLE_SEL_INTR 0x02
2507#define ADV_INTR_ENABLE_DPR_INTR 0x04
2508#define ADV_INTR_ENABLE_RTA_INTR 0x08
2509#define ADV_INTR_ENABLE_RMA_INTR 0x10
2510#define ADV_INTR_ENABLE_RST_INTR 0x20
2511#define ADV_INTR_ENABLE_DPE_INTR 0x40
2512#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
2513
2514#define ADV_INTR_STATUS_INTRA 0x01
2515#define ADV_INTR_STATUS_INTRB 0x02
2516#define ADV_INTR_STATUS_INTRC 0x04
2517
2518#define ADV_RISC_CSR_STOP (0x0000)
2519#define ADV_RISC_TEST_COND (0x2000)
2520#define ADV_RISC_CSR_RUN (0x4000)
2521#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
2522
2523#define ADV_CTRL_REG_HOST_INTR 0x0100
2524#define ADV_CTRL_REG_SEL_INTR 0x0200
2525#define ADV_CTRL_REG_DPR_INTR 0x0400
2526#define ADV_CTRL_REG_RTA_INTR 0x0800
2527#define ADV_CTRL_REG_RMA_INTR 0x1000
2528#define ADV_CTRL_REG_RES_BIT14 0x2000
2529#define ADV_CTRL_REG_DPE_INTR 0x4000
2530#define ADV_CTRL_REG_POWER_DONE 0x8000
2531#define ADV_CTRL_REG_ANY_INTR 0xFF00
2532
2533#define ADV_CTRL_REG_CMD_RESET 0x00C6
2534#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
2535#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
2536#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
2537#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
2538
2539#define ADV_TICKLE_NOP 0x00
2540#define ADV_TICKLE_A 0x01
2541#define ADV_TICKLE_B 0x02
2542#define ADV_TICKLE_C 0x03
2543
2544#define ADV_SCSI_CTRL_RSTOUT 0x2000
2545
2546#define AdvIsIntPending(port) \
2547 (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
2548
2549/*
2550 * SCSI_CFG0 Register bit definitions
2551 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002552#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
2553#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
2554#define EVEN_PARITY 0x1000 /* Select Even Parity */
2555#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
2556#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
2557#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
2558#define SCAM_EN 0x0080 /* Enable SCAM selection */
2559#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
2560#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
2561#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
2562#define OUR_ID 0x000F /* SCSI ID */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563
2564/*
2565 * SCSI_CFG1 Register bit definitions
2566 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002567#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
2568#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
2569#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
2570#define FILTER_SEL 0x0C00 /* Filter Period Selection */
2571#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
2572#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
2573#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
2574#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
2575#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
2576#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
2577#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
2578#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
2579#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
2580#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
2581#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582
2583/*
2584 * Addendum for ASC-38C0800 Chip
2585 *
2586 * The ASC-38C1600 Chip uses the same definitions except that the
2587 * bus mode override bits [12:10] have been moved to byte register
2588 * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
2589 * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
2590 * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
2591 * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
2592 * and [1:0]. Bits [14], [7:6], [3:2] are unused.
2593 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002594#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */
2595#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */
2596#define HVD 0x1000 /* HVD Device Detect */
2597#define LVD 0x0800 /* LVD Device Detect */
2598#define SE 0x0400 /* SE Device Detect */
2599#define TERM_LVD 0x00C0 /* LVD Termination Bits */
2600#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */
2601#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */
2602#define TERM_SE 0x0030 /* SE Termination Bits */
2603#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */
2604#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */
2605#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */
2606#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */
2607#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */
2608#define C_DET_SE 0x0003 /* SE Cable Detect Bits */
2609#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */
2610#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
2612#define CABLE_ILLEGAL_A 0x7
2613 /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
2614
2615#define CABLE_ILLEGAL_B 0xB
2616 /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
2617
2618/*
2619 * MEM_CFG Register bit definitions
2620 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002621#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
2622#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
2623#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
2624#define RAM_SZ_2KB 0x00 /* 2 KB */
2625#define RAM_SZ_4KB 0x04 /* 4 KB */
2626#define RAM_SZ_8KB 0x08 /* 8 KB */
2627#define RAM_SZ_16KB 0x0C /* 16 KB */
2628#define RAM_SZ_32KB 0x10 /* 32 KB */
2629#define RAM_SZ_64KB 0x14 /* 64 KB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630
2631/*
2632 * DMA_CFG0 Register bit definitions
2633 *
2634 * This register is only accessible to the host.
2635 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002636#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
2637#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
2638#define FIFO_THRESH_16B 0x00 /* 16 bytes */
2639#define FIFO_THRESH_32B 0x20 /* 32 bytes */
2640#define FIFO_THRESH_48B 0x30 /* 48 bytes */
2641#define FIFO_THRESH_64B 0x40 /* 64 bytes */
2642#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
2643#define FIFO_THRESH_96B 0x60 /* 96 bytes */
2644#define FIFO_THRESH_112B 0x70 /* 112 bytes */
2645#define START_CTL 0x0C /* DMA start conditions */
2646#define START_CTL_TH 0x00 /* Wait threshold level (default) */
2647#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
2648#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
2649#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
2650#define READ_CMD 0x03 /* Memory Read Method */
2651#define READ_CMD_MR 0x00 /* Memory Read */
2652#define READ_CMD_MRL 0x02 /* Memory Read Long */
2653#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
2655/*
2656 * ASC-38C0800 RAM BIST Register bit definitions
2657 */
2658#define RAM_TEST_MODE 0x80
2659#define PRE_TEST_MODE 0x40
2660#define NORMAL_MODE 0x00
2661#define RAM_TEST_DONE 0x10
2662#define RAM_TEST_STATUS 0x0F
2663#define RAM_TEST_HOST_ERROR 0x08
2664#define RAM_TEST_INTRAM_ERROR 0x04
2665#define RAM_TEST_RISC_ERROR 0x02
2666#define RAM_TEST_SCSI_ERROR 0x01
2667#define RAM_TEST_SUCCESS 0x00
2668#define PRE_TEST_VALUE 0x05
2669#define NORMAL_VALUE 0x00
2670
2671/*
2672 * ASC38C1600 Definitions
2673 *
2674 * IOPB_PCI_INT_CFG Bit Field Definitions
2675 */
2676
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002677#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678
2679/*
2680 * Bit 1 can be set to change the interrupt for the Function to operate in
2681 * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
2682 * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
2683 * mode, otherwise the operating mode is undefined.
2684 */
2685#define TOTEMPOLE 0x02
2686
2687/*
2688 * Bit 0 can be used to change the Int Pin for the Function. The value is
2689 * 0 by default for both Functions with Function 0 using INT A and Function
2690 * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
2691 * INT A is used.
2692 *
2693 * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
2694 * value specified in the PCI Configuration Space.
2695 */
2696#define INTAB 0x01
2697
2698/* a_advlib.h */
2699
2700/*
2701 * Adv Library Status Definitions
2702 */
2703#define ADV_TRUE 1
2704#define ADV_FALSE 0
2705#define ADV_NOERROR 1
2706#define ADV_SUCCESS 1
2707#define ADV_BUSY 0
2708#define ADV_ERROR (-1)
2709
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710/*
2711 * ADV_DVC_VAR 'warn_code' values
2712 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002713#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */
2714#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
2715#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
2716#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
2717#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002719#define ADV_MAX_TID 15 /* max. target identifier */
2720#define ADV_MAX_LUN 7 /* max. logical unit number */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721
2722/*
2723 * Error code values are set in ADV_DVC_VAR 'err_code'.
2724 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002725#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
2726#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
2727#define ASC_IERR_NO_CARRIER 0x0004 /* No more carrier memory. */
2728#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
2729#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
2730#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
2731#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD attached to LVD connector. */
2732#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
2733#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
2734#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
2735#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
2736#define ASC_IERR_BIST_PRE_TEST 0x2000 /* BIST pre-test error */
2737#define ASC_IERR_BIST_RAM_TEST 0x4000 /* BIST RAM test error */
2738#define ASC_IERR_BAD_CHIPTYPE 0x8000 /* Invalid 'chip_type' setting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739
2740/*
2741 * Fixed locations of microcode operating variables.
2742 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002743#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
2744#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
2745#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
2746#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
2747#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
2748#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
2749#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
2750#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */
2751#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */
2752#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */
2753#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */
2754#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */
2755#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756#define ASC_MC_CHIP_TYPE 0x009A
2757#define ASC_MC_INTRB_CODE 0x009B
2758#define ASC_MC_WDTR_ABLE 0x009C
2759#define ASC_MC_SDTR_ABLE 0x009E
2760#define ASC_MC_TAGQNG_ABLE 0x00A0
2761#define ASC_MC_DISC_ENABLE 0x00A2
2762#define ASC_MC_IDLE_CMD_STATUS 0x00A4
2763#define ASC_MC_IDLE_CMD 0x00A6
2764#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8
2765#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
2766#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
2767#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
2768#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
2769#define ASC_MC_SDTR_DONE 0x00B6
2770#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
2771#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
2772#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002773#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774#define ASC_MC_WDTR_DONE 0x0124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002775#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776#define ASC_MC_ICQ 0x0160
2777#define ASC_MC_IRQ 0x0164
2778#define ASC_MC_PPR_ABLE 0x017A
2779
2780/*
2781 * BIOS LRAM variable absolute offsets.
2782 */
2783#define BIOS_CODESEG 0x54
2784#define BIOS_CODELEN 0x56
2785#define BIOS_SIGNATURE 0x58
2786#define BIOS_VERSION 0x5A
2787
2788/*
2789 * Microcode Control Flags
2790 *
2791 * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
2792 * and handled by the microcode.
2793 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002794#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
2795#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
2797/*
2798 * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
2799 */
2800#define HSHK_CFG_WIDE_XFR 0x8000
2801#define HSHK_CFG_RATE 0x0F00
2802#define HSHK_CFG_OFFSET 0x001F
2803
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002804#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
2805#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
2806#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
2807#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002809#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */
2810#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */
2811#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
2812#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */
2813#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002815#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */
2816#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */
2817#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */
2818#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */
2819#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820/*
2821 * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
2822 * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
2823 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002824#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */
2825#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826
2827/*
2828 * All fields here are accessed by the board microcode and need to be
2829 * little-endian.
2830 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002831typedef struct adv_carr_t {
2832 ADV_VADDR carr_va; /* Carrier Virtual Address */
2833 ADV_PADDR carr_pa; /* Carrier Physical Address */
2834 ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */
2835 /*
2836 * next_vpa [31:4] Carrier Virtual or Physical Next Pointer
2837 *
2838 * next_vpa [3:1] Reserved Bits
2839 * next_vpa [0] Done Flag set in Response Queue.
2840 */
2841 ADV_VADDR next_vpa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842} ADV_CARR_T;
2843
2844/*
2845 * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
2846 */
2847#define ASC_NEXT_VPA_MASK 0xFFFFFFF0
2848
2849#define ASC_RQ_DONE 0x00000001
2850#define ASC_RQ_GOOD 0x00000002
2851#define ASC_CQ_STOPPER 0x00000000
2852
2853#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
2854
2855#define ADV_CARRIER_NUM_PAGE_CROSSING \
2856 (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
2857 (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
2858
2859#define ADV_CARRIER_BUFSIZE \
2860 ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
2861
2862/*
2863 * ASC_SCSI_REQ_Q 'a_flag' definitions
2864 *
2865 * The Adv Library should limit use to the lower nibble (4 bits) of
2866 * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
2867 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002868#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
2869#define ADV_SCSIQ_DONE 0x02 /* request done */
2870#define ADV_DONT_RETRY 0x08 /* don't do retry */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002872#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */
2873#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */
2874#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875
2876/*
2877 * Adapter temporary configuration structure
2878 *
2879 * This structure can be discarded after initialization. Don't add
2880 * fields here needed after initialization.
2881 *
2882 * Field naming convention:
2883 *
2884 * *_enable indicates the field enables or disables a feature. The
2885 * value of the field is never reset.
2886 */
2887typedef struct adv_dvc_cfg {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002888 ushort disc_enable; /* enable disconnection */
2889 uchar chip_version; /* chip version */
2890 uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
2891 ushort lib_version; /* Adv Library version number */
2892 ushort control_flag; /* Microcode Control Flag */
2893 ushort mcode_date; /* Microcode date */
2894 ushort mcode_version; /* Microcode version */
2895 ushort pci_slot_info; /* high byte device/function number */
2896 /* bits 7-3 device num., bits 2-0 function num. */
2897 /* low byte bus num. */
2898 ushort serial1; /* EEPROM serial number word 1 */
2899 ushort serial2; /* EEPROM serial number word 2 */
2900 ushort serial3; /* EEPROM serial number word 3 */
2901 struct device *dev; /* pointer to the pci dev structure for this board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902} ADV_DVC_CFG;
2903
2904struct adv_dvc_var;
2905struct adv_scsi_req_q;
2906
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002907typedef void (*ADV_ISR_CALLBACK)
2908 (struct adv_dvc_var *, struct adv_scsi_req_q *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002910typedef void (*ADV_ASYNC_CALLBACK)
2911 (struct adv_dvc_var *, uchar);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
2913/*
2914 * Adapter operation variable structure.
2915 *
2916 * One structure is required per host adapter.
2917 *
2918 * Field naming convention:
2919 *
2920 * *_able indicates both whether a feature should be enabled or disabled
2921 * and whether a device isi capable of the feature. At initialization
2922 * this field may be set, but later if a device is found to be incapable
2923 * of the feature, the field is cleared.
2924 */
2925typedef struct adv_dvc_var {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002926 AdvPortAddr iop_base; /* I/O port address */
2927 ushort err_code; /* fatal error code */
2928 ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
2929 ADV_ISR_CALLBACK isr_callback;
2930 ADV_ASYNC_CALLBACK async_callback;
2931 ushort wdtr_able; /* try WDTR for a device */
2932 ushort sdtr_able; /* try SDTR for a device */
2933 ushort ultra_able; /* try SDTR Ultra speed for a device */
2934 ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */
2935 ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */
2936 ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */
2937 ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */
2938 ushort tagqng_able; /* try tagged queuing with a device */
2939 ushort ppr_able; /* PPR message capable per TID bitmask. */
2940 uchar max_dvc_qng; /* maximum number of tagged commands per device */
2941 ushort start_motor; /* start motor command allowed */
2942 uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
2943 uchar chip_no; /* should be assigned by caller */
2944 uchar max_host_qng; /* maximum number of Q'ed command allowed */
2945 uchar irq_no; /* IRQ number */
2946 ushort no_scam; /* scam_tolerant of EEPROM */
2947 struct asc_board *drv_ptr; /* driver pointer to private structure */
2948 uchar chip_scsi_id; /* chip SCSI target ID */
2949 uchar chip_type;
2950 uchar bist_err_code;
2951 ADV_CARR_T *carrier_buf;
2952 ADV_CARR_T *carr_freelist; /* Carrier free list. */
2953 ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */
2954 ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */
2955 ushort carr_pending_cnt; /* Count of pending carriers. */
2956 /*
2957 * Note: The following fields will not be used after initialization. The
2958 * driver may discard the buffer after initialization is done.
2959 */
2960 ADV_DVC_CFG *cfg; /* temporary configuration structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961} ADV_DVC_VAR;
2962
2963#define NO_OF_SG_PER_BLOCK 15
2964
2965typedef struct asc_sg_block {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002966 uchar reserved1;
2967 uchar reserved2;
2968 uchar reserved3;
2969 uchar sg_cnt; /* Valid entries in block. */
2970 ADV_PADDR sg_ptr; /* Pointer to next sg block. */
2971 struct {
2972 ADV_PADDR sg_addr; /* SG element address. */
2973 ADV_DCNT sg_count; /* SG element count. */
2974 } sg_list[NO_OF_SG_PER_BLOCK];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975} ADV_SG_BLOCK;
2976
2977/*
2978 * ADV_SCSI_REQ_Q - microcode request structure
2979 *
2980 * All fields in this structure up to byte 60 are used by the microcode.
2981 * The microcode makes assumptions about the size and ordering of fields
2982 * in this structure. Do not change the structure definition here without
2983 * coordinating the change with the microcode.
2984 *
2985 * All fields accessed by microcode must be maintained in little_endian
2986 * order.
2987 */
2988typedef struct adv_scsi_req_q {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04002989 uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
2990 uchar target_cmd;
2991 uchar target_id; /* Device target identifier. */
2992 uchar target_lun; /* Device target logical unit number. */
2993 ADV_PADDR data_addr; /* Data buffer physical address. */
2994 ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */
2995 ADV_PADDR sense_addr;
2996 ADV_PADDR carr_pa;
2997 uchar mflag;
2998 uchar sense_len;
2999 uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */
3000 uchar scsi_cntl;
3001 uchar done_status; /* Completion status. */
3002 uchar scsi_status; /* SCSI status byte. */
3003 uchar host_status; /* Ucode host status. */
3004 uchar sg_working_ix;
3005 uchar cdb[12]; /* SCSI CDB bytes 0-11. */
3006 ADV_PADDR sg_real_addr; /* SG list physical address. */
3007 ADV_PADDR scsiq_rptr;
3008 uchar cdb16[4]; /* SCSI CDB bytes 12-15. */
3009 ADV_VADDR scsiq_ptr;
3010 ADV_VADDR carr_va;
3011 /*
3012 * End of microcode structure - 60 bytes. The rest of the structure
3013 * is used by the Adv Library and ignored by the microcode.
3014 */
3015 ADV_VADDR srb_ptr;
3016 ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
3017 char *vdata_addr; /* Data buffer virtual address. */
3018 uchar a_flag;
3019 uchar pad[2]; /* Pad out to a word boundary. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020} ADV_SCSI_REQ_Q;
3021
3022/*
3023 * Microcode idle loop commands
3024 */
3025#define IDLE_CMD_COMPLETED 0
3026#define IDLE_CMD_STOP_CHIP 0x0001
3027#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
3028#define IDLE_CMD_SEND_INT 0x0004
3029#define IDLE_CMD_ABORT 0x0008
3030#define IDLE_CMD_DEVICE_RESET 0x0010
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003031#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */
3032#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033#define IDLE_CMD_SCSIREQ 0x0080
3034
3035#define IDLE_CMD_STATUS_SUCCESS 0x0001
3036#define IDLE_CMD_STATUS_FAILURE 0x0002
3037
3038/*
3039 * AdvSendIdleCmd() flag definitions.
3040 */
3041#define ADV_NOWAIT 0x01
3042
3043/*
3044 * Wait loop time out values.
3045 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003046#define SCSI_WAIT_10_SEC 10UL /* 10 seconds */
3047#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */
3048#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */
3049#define SCSI_MS_PER_SEC 1000UL /* milliseconds per second */
3050#define SCSI_MAX_RETRY 10 /* retry count */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003052#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */
3053#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */
3054#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
3055#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003057#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058
3059/*
3060 * Device drivers must define the following functions.
3061 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003062static inline ulong DvcEnterCritical(void);
3063static inline void DvcLeaveCritical(ulong);
3064static void DvcSleepMilliSecond(ADV_DCNT);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003065static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
3066 uchar *, ASC_SDCNT *, int);
3067static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
3069/*
3070 * Adv Library functions available to drivers.
3071 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003072static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3073static int AdvISR(ADV_DVC_VAR *);
3074static int AdvInitGetConfig(ADV_DVC_VAR *);
3075static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
3076static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
3077static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
3078static int AdvResetChipAndSB(ADV_DVC_VAR *);
3079static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
3081/*
3082 * Internal Adv Library functions.
3083 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003084static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
3085static void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3086static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
3087static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
3088static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
3089static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3090static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
3091static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3092static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
3093static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3094static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
3095static void AdvWaitEEPCmd(AdvPortAddr);
3096static ushort AdvReadEEPWord(AdvPortAddr, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098/* Read byte from a register. */
3099#define AdvReadByteRegister(iop_base, reg_off) \
3100 (ADV_MEM_READB((iop_base) + (reg_off)))
3101
3102/* Write byte to a register. */
3103#define AdvWriteByteRegister(iop_base, reg_off, byte) \
3104 (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
3105
3106/* Read word (2 bytes) from a register. */
3107#define AdvReadWordRegister(iop_base, reg_off) \
3108 (ADV_MEM_READW((iop_base) + (reg_off)))
3109
3110/* Write word (2 bytes) to a register. */
3111#define AdvWriteWordRegister(iop_base, reg_off, word) \
3112 (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
3113
3114/* Write dword (4 bytes) to a register. */
3115#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
3116 (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
3117
3118/* Read byte from LRAM. */
3119#define AdvReadByteLram(iop_base, addr, byte) \
3120do { \
3121 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3122 (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
3123} while (0)
3124
3125/* Write byte to LRAM. */
3126#define AdvWriteByteLram(iop_base, addr, byte) \
3127 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3128 ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
3129
3130/* Read word (2 bytes) from LRAM. */
3131#define AdvReadWordLram(iop_base, addr, word) \
3132do { \
3133 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
3134 (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
3135} while (0)
3136
3137/* Write word (2 bytes) to LRAM. */
3138#define AdvWriteWordLram(iop_base, addr, word) \
3139 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3140 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3141
3142/* Write little-endian double word (4 bytes) to LRAM */
3143/* Because of unspecified C language ordering don't use auto-increment. */
3144#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
3145 ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
3146 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3147 cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
3148 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
3149 ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
3150 cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
3151
3152/* Read word (2 bytes) from LRAM assuming that the address is already set. */
3153#define AdvReadWordAutoIncLram(iop_base) \
3154 (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
3155
3156/* Write word (2 bytes) to LRAM assuming that the address is already set. */
3157#define AdvWriteWordAutoIncLram(iop_base, word) \
3158 (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
3159
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160/*
3161 * Define macro to check for Condor signature.
3162 *
3163 * Evaluate to ADV_TRUE if a Condor chip is found the specified port
3164 * address 'iop_base'. Otherwise evalue to ADV_FALSE.
3165 */
3166#define AdvFindSignature(iop_base) \
3167 (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
3168 ADV_CHIP_ID_BYTE) && \
3169 (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
3170 ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
3171
3172/*
3173 * Define macro to Return the version number of the chip at 'iop_base'.
3174 *
3175 * The second parameter 'bus_type' is currently unused.
3176 */
3177#define AdvGetChipVersion(iop_base, bus_type) \
3178 AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
3179
3180/*
3181 * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
3182 * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
3183 *
3184 * If the request has not yet been sent to the device it will simply be
3185 * aborted from RISC memory. If the request is disconnected it will be
3186 * aborted on reselection by sending an Abort Message to the target ID.
3187 *
3188 * Return value:
3189 * ADV_TRUE(1) - Queue was successfully aborted.
3190 * ADV_FALSE(0) - Queue was not found on the active queue list.
3191 */
3192#define AdvAbortQueue(asc_dvc, scsiq) \
3193 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
3194 (ADV_DCNT) (scsiq))
3195
3196/*
3197 * Send a Bus Device Reset Message to the specified target ID.
3198 *
3199 * All outstanding commands will be purged if sending the
3200 * Bus Device Reset Message is successful.
3201 *
3202 * Return Value:
3203 * ADV_TRUE(1) - All requests on the target are purged.
3204 * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
3205 * are not purged.
3206 */
3207#define AdvResetDevice(asc_dvc, target_id) \
3208 AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
3209 (ADV_DCNT) (target_id))
3210
3211/*
3212 * SCSI Wide Type definition.
3213 */
3214#define ADV_SCSI_BIT_ID_TYPE ushort
3215
3216/*
3217 * AdvInitScsiTarget() 'cntl_flag' options.
3218 */
3219#define ADV_SCAN_LUN 0x01
3220#define ADV_CAPINFO_NOLUN 0x02
3221
3222/*
3223 * Convert target id to target id bit mask.
3224 */
3225#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
3226
3227/*
3228 * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
3229 */
3230
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003231#define QD_NO_STATUS 0x00 /* Request not completed yet. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232#define QD_NO_ERROR 0x01
3233#define QD_ABORTED_BY_HOST 0x02
3234#define QD_WITH_ERROR 0x04
3235
3236#define QHSTA_NO_ERROR 0x00
3237#define QHSTA_M_SEL_TIMEOUT 0x11
3238#define QHSTA_M_DATA_OVER_RUN 0x12
3239#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
3240#define QHSTA_M_QUEUE_ABORTED 0x15
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003241#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
3242#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
3243#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
3244#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
3245#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
3246#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
3247#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003249#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
3250#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
3251#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
3252#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */
3253#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
3254#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */
3255#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */
3256#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257#define QHSTA_M_WTM_TIMEOUT 0x41
3258#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
3259#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
3260#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003261#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
3262#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */
3263#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264
3265/*
3266 * Default EEPROM Configuration structure defined in a_init.c.
3267 */
3268static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
3269static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
3270static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
3271
3272/*
3273 * DvcGetPhyAddr() flag arguments
3274 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003275#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
3276#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
3277#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
3278#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
3279#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
3280#define ADV_IS_CARRIER_FLAG 0x20 /* 'addr' is ADV_CARR_T pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281
3282/* Return the address that is aligned at the next doubleword >= to 'addr'. */
3283#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7)
3284#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF)
3285#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F)
3286
3287/*
3288 * Total contiguous memory needed for driver SG blocks.
3289 *
3290 * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
3291 * number of scatter-gather elements the driver supports in a
3292 * single request.
3293 */
3294
3295#define ADV_SG_LIST_MAX_BYTE_SIZE \
3296 (sizeof(ADV_SG_BLOCK) * \
3297 ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
3298
3299/*
3300 * Inquiry data structure and bitfield macros
3301 *
3302 * Using bitfields to access the subchar data isn't portable across
3303 * endianness, so instead mask and shift. Only quantities of more
3304 * than 1 bit are shifted, since the others are just tested for true
3305 * or false.
3306 */
3307
3308#define ADV_INQ_DVC_TYPE(inq) ((inq)->periph & 0x1f)
3309#define ADV_INQ_QUALIFIER(inq) (((inq)->periph & 0xe0) >> 5)
3310#define ADV_INQ_DVC_TYPE_MOD(inq) ((inq)->devtype & 0x7f)
3311#define ADV_INQ_REMOVABLE(inq) ((inq)->devtype & 0x80)
3312#define ADV_INQ_ANSI_VER(inq) ((inq)->ver & 0x07)
3313#define ADV_INQ_ECMA_VER(inq) (((inq)->ver & 0x38) >> 3)
3314#define ADV_INQ_ISO_VER(inq) (((inq)->ver & 0xc0) >> 6)
3315#define ADV_INQ_RESPONSE_FMT(inq) ((inq)->byte3 & 0x0f)
3316#define ADV_INQ_TERM_IO(inq) ((inq)->byte3 & 0x40)
3317#define ADV_INQ_ASYNC_NOTIF(inq) ((inq)->byte3 & 0x80)
3318#define ADV_INQ_SOFT_RESET(inq) ((inq)->flags & 0x01)
3319#define ADV_INQ_CMD_QUEUE(inq) ((inq)->flags & 0x02)
3320#define ADV_INQ_LINK_CMD(inq) ((inq)->flags & 0x08)
3321#define ADV_INQ_SYNC(inq) ((inq)->flags & 0x10)
3322#define ADV_INQ_WIDE16(inq) ((inq)->flags & 0x20)
3323#define ADV_INQ_WIDE32(inq) ((inq)->flags & 0x40)
3324#define ADV_INQ_REL_ADDR(inq) ((inq)->flags & 0x80)
3325#define ADV_INQ_INFO_UNIT(inq) ((inq)->info & 0x01)
3326#define ADV_INQ_QUICK_ARB(inq) ((inq)->info & 0x02)
3327#define ADV_INQ_CLOCKING(inq) (((inq)->info & 0x0c) >> 2)
3328
3329typedef struct {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003330 uchar periph; /* peripheral device type [0:4] */
3331 /* peripheral qualifier [5:7] */
3332 uchar devtype; /* device type modifier (for SCSI I) [0:6] */
3333 /* RMB - removable medium bit [7] */
3334 uchar ver; /* ANSI approved version [0:2] */
3335 /* ECMA version [3:5] */
3336 /* ISO version [6:7] */
3337 uchar byte3; /* response data format [0:3] */
3338 /* 0 SCSI 1 */
3339 /* 1 CCS */
3340 /* 2 SCSI-2 */
3341 /* 3-F reserved */
3342 /* reserved [4:5] */
3343 /* terminate I/O process bit (see 5.6.22) [6] */
3344 /* asynch. event notification (processor) [7] */
3345 uchar add_len; /* additional length */
3346 uchar res1; /* reserved */
3347 uchar res2; /* reserved */
3348 uchar flags; /* soft reset implemented [0] */
3349 /* command queuing [1] */
3350 /* reserved [2] */
3351 /* linked command for this logical unit [3] */
3352 /* synchronous data transfer [4] */
3353 /* wide bus 16 bit data transfer [5] */
3354 /* wide bus 32 bit data transfer [6] */
3355 /* relative addressing mode [7] */
3356 uchar vendor_id[8]; /* vendor identification */
3357 uchar product_id[16]; /* product identification */
3358 uchar product_rev_level[4]; /* product revision level */
3359 uchar vendor_specific[20]; /* vendor specific */
3360 uchar info; /* information unit supported [0] */
3361 /* quick arbitrate supported [1] */
3362 /* clocking field [2:3] */
3363 /* reserved [4:7] */
3364 uchar res3; /* reserved */
3365} ADV_SCSI_INQUIRY; /* 58 bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366
3367/*
3368 * --- Driver Constants and Macros
3369 */
3370
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371/* Reference Scsi_Host hostdata */
3372#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
3373
3374/* asc_board_t flags */
3375#define ASC_HOST_IN_RESET 0x01
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003376#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377#define ASC_SELECT_QUEUE_DEPTHS 0x08
3378
3379#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
3380#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
3381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003382#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003384#define ASC_INFO_SIZE 128 /* advansys_info() line size */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385
3386#ifdef CONFIG_PROC_FS
3387/* /proc/scsi/advansys/[0...] related definitions */
3388#define ASC_PRTBUF_SIZE 2048
3389#define ASC_PRTLINE_SIZE 160
3390
3391#define ASC_PRT_NEXT() \
3392 if (cp) { \
3393 totlen += len; \
3394 leftlen -= len; \
3395 if (leftlen == 0) { \
3396 return totlen; \
3397 } \
3398 cp += len; \
3399 }
3400#endif /* CONFIG_PROC_FS */
3401
3402/* Asc Library return codes */
3403#define ASC_TRUE 1
3404#define ASC_FALSE 0
3405#define ASC_NOERROR 1
3406#define ASC_BUSY 0
3407#define ASC_ERROR (-1)
3408
3409/* struct scsi_cmnd function return codes */
3410#define STATUS_BYTE(byte) (byte)
3411#define MSG_BYTE(byte) ((byte) << 8)
3412#define HOST_BYTE(byte) ((byte) << 16)
3413#define DRIVER_BYTE(byte) ((byte) << 24)
3414
3415/*
3416 * The following definitions and macros are OS independent interfaces to
3417 * the queue functions:
3418 * REQ - SCSI request structure
3419 * REQP - pointer to SCSI request structure
3420 * REQPTID(reqp) - reqp's target id
3421 * REQPNEXT(reqp) - reqp's next pointer
3422 * REQPNEXTP(reqp) - pointer to reqp's next pointer
3423 * REQPTIME(reqp) - reqp's time stamp value
3424 * REQTIMESTAMP() - system time stamp value
3425 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003426typedef struct scsi_cmnd REQ, *REQP;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
3428#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
3429#define REQPTID(reqp) ((reqp)->device->id)
3430#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
3431#define REQTIMESTAMP() (jiffies)
3432
3433#define REQTIMESTAT(function, ascq, reqp, tid) \
3434{ \
3435 /*
3436 * If the request time stamp is less than the system time stamp, then \
3437 * maybe the system time stamp wrapped. Set the request time to zero.\
3438 */ \
3439 if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
3440 REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
3441 } else { \
3442 /* Indicate an error occurred with the assertion. */ \
3443 ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
3444 REQPTIME(reqp) = 0; \
3445 } \
3446 /* Handle first minimum time case without external initialization. */ \
3447 if (((ascq)->q_tot_cnt[tid] == 1) || \
3448 (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
3449 (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
3450 ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
3451 (function), (tid), (ascq)->q_min_tim[tid]); \
3452 } \
3453 if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
3454 (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
3455 ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
3456 (function), tid, (ascq)->q_max_tim[tid]); \
3457 } \
3458 (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
3459 /* Reset the time stamp field. */ \
3460 REQPTIME(reqp) = 0; \
3461}
3462
3463/* asc_enqueue() flags */
3464#define ASC_FRONT 1
3465#define ASC_BACK 2
3466
3467/* asc_dequeue_list() argument */
3468#define ASC_TID_ALL (-1)
3469
3470/* Return non-zero, if the queue is empty. */
3471#define ASC_QUEUE_EMPTY(ascq) ((ascq)->q_tidmask == 0)
3472
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473#ifndef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003474#define ASC_STATS(shost, counter)
3475#define ASC_STATS_ADD(shost, counter, count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476#else /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003477#define ASC_STATS(shost, counter) \
3478 (ASC_BOARDP(shost)->asc_stats.counter++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003480#define ASC_STATS_ADD(shost, counter, count) \
3481 (ASC_BOARDP(shost)->asc_stats.counter += (count))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482#endif /* ADVANSYS_STATS */
3483
3484#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
3485
3486/* If the result wraps when calculating tenths, return 0. */
3487#define ASC_TENTHS(num, den) \
3488 (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
3489 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
3490
3491/*
3492 * Display a message to the console.
3493 */
3494#define ASC_PRINT(s) \
3495 { \
3496 printk("advansys: "); \
3497 printk(s); \
3498 }
3499
3500#define ASC_PRINT1(s, a1) \
3501 { \
3502 printk("advansys: "); \
3503 printk((s), (a1)); \
3504 }
3505
3506#define ASC_PRINT2(s, a1, a2) \
3507 { \
3508 printk("advansys: "); \
3509 printk((s), (a1), (a2)); \
3510 }
3511
3512#define ASC_PRINT3(s, a1, a2, a3) \
3513 { \
3514 printk("advansys: "); \
3515 printk((s), (a1), (a2), (a3)); \
3516 }
3517
3518#define ASC_PRINT4(s, a1, a2, a3, a4) \
3519 { \
3520 printk("advansys: "); \
3521 printk((s), (a1), (a2), (a3), (a4)); \
3522 }
3523
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524#ifndef ADVANSYS_DEBUG
3525
3526#define ASC_DBG(lvl, s)
3527#define ASC_DBG1(lvl, s, a1)
3528#define ASC_DBG2(lvl, s, a1, a2)
3529#define ASC_DBG3(lvl, s, a1, a2, a3)
3530#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
3531#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
3532#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
3533#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
3534#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3535#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
3536#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
3537#define ASC_DBG_PRT_HEX(lvl, name, start, length)
3538#define ASC_DBG_PRT_CDB(lvl, cdb, len)
3539#define ASC_DBG_PRT_SENSE(lvl, sense, len)
3540#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
3541
3542#else /* ADVANSYS_DEBUG */
3543
3544/*
3545 * Debugging Message Levels:
3546 * 0: Errors Only
3547 * 1: High-Level Tracing
3548 * 2-N: Verbose Tracing
3549 */
3550
3551#define ASC_DBG(lvl, s) \
3552 { \
3553 if (asc_dbglvl >= (lvl)) { \
3554 printk(s); \
3555 } \
3556 }
3557
3558#define ASC_DBG1(lvl, s, a1) \
3559 { \
3560 if (asc_dbglvl >= (lvl)) { \
3561 printk((s), (a1)); \
3562 } \
3563 }
3564
3565#define ASC_DBG2(lvl, s, a1, a2) \
3566 { \
3567 if (asc_dbglvl >= (lvl)) { \
3568 printk((s), (a1), (a2)); \
3569 } \
3570 }
3571
3572#define ASC_DBG3(lvl, s, a1, a2, a3) \
3573 { \
3574 if (asc_dbglvl >= (lvl)) { \
3575 printk((s), (a1), (a2), (a3)); \
3576 } \
3577 }
3578
3579#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
3580 { \
3581 if (asc_dbglvl >= (lvl)) { \
3582 printk((s), (a1), (a2), (a3), (a4)); \
3583 } \
3584 }
3585
3586#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
3587 { \
3588 if (asc_dbglvl >= (lvl)) { \
3589 asc_prt_scsi_host(s); \
3590 } \
3591 }
3592
3593#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
3594 { \
3595 if (asc_dbglvl >= (lvl)) { \
3596 asc_prt_scsi_cmnd(s); \
3597 } \
3598 }
3599
3600#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
3601 { \
3602 if (asc_dbglvl >= (lvl)) { \
3603 asc_prt_asc_scsi_q(scsiqp); \
3604 } \
3605 }
3606
3607#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
3608 { \
3609 if (asc_dbglvl >= (lvl)) { \
3610 asc_prt_asc_qdone_info(qdone); \
3611 } \
3612 }
3613
3614#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
3615 { \
3616 if (asc_dbglvl >= (lvl)) { \
3617 asc_prt_adv_scsi_req_q(scsiqp); \
3618 } \
3619 }
3620
3621#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
3622 { \
3623 if (asc_dbglvl >= (lvl)) { \
3624 asc_prt_hex((name), (start), (length)); \
3625 } \
3626 }
3627
3628#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
3629 ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
3630
3631#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
3632 ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
3633
3634#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
3635 ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
3636#endif /* ADVANSYS_DEBUG */
3637
3638#ifndef ADVANSYS_ASSERT
3639#define ASC_ASSERT(a)
3640#else /* ADVANSYS_ASSERT */
3641
3642#define ASC_ASSERT(a) \
3643 { \
3644 if (!(a)) { \
3645 printk("ASC_ASSERT() Failure: file %s, line %d\n", \
3646 __FILE__, __LINE__); \
3647 } \
3648 }
3649
3650#endif /* ADVANSYS_ASSERT */
3651
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652/*
3653 * --- Driver Structures
3654 */
3655
3656#ifdef ADVANSYS_STATS
3657
3658/* Per board statistics structure */
3659struct asc_stats {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003660 /* Driver Entrypoint Statistics */
3661 ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */
3662 ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */
3663 ADV_DCNT biosparam; /* # calls to advansys_biosparam() */
3664 ADV_DCNT interrupt; /* # advansys_interrupt() calls */
3665 ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */
3666 ADV_DCNT done; /* # calls to request's scsi_done function */
3667 ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
3668 ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
3669 ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
3670 /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
3671 ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */
3672 ADV_DCNT exe_busy; /* # ASC_BUSY returns. */
3673 ADV_DCNT exe_error; /* # ASC_ERROR returns. */
3674 ADV_DCNT exe_unknown; /* # unknown returns. */
3675 /* Data Transfer Statistics */
3676 ADV_DCNT cont_cnt; /* # non-scatter-gather I/O requests received */
3677 ADV_DCNT cont_xfer; /* # contiguous transfer 512-bytes */
3678 ADV_DCNT sg_cnt; /* # scatter-gather I/O requests received */
3679 ADV_DCNT sg_elem; /* # scatter-gather elements */
3680 ADV_DCNT sg_xfer; /* # scatter-gather transfer 512-bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681};
3682#endif /* ADVANSYS_STATS */
3683
3684/*
3685 * Request queuing structure
3686 */
3687typedef struct asc_queue {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003688 ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
3689 REQP q_first[ADV_MAX_TID + 1]; /* first queued request */
3690 REQP q_last[ADV_MAX_TID + 1]; /* last queued request */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003692 short q_cur_cnt[ADV_MAX_TID + 1]; /* current queue count */
3693 short q_max_cnt[ADV_MAX_TID + 1]; /* maximum queue count */
3694 ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1]; /* total enqueue count */
3695 ADV_DCNT q_tot_tim[ADV_MAX_TID + 1]; /* total time queued */
3696 ushort q_max_tim[ADV_MAX_TID + 1]; /* maximum time queued */
3697 ushort q_min_tim[ADV_MAX_TID + 1]; /* minimum time queued */
3698#endif /* ADVANSYS_STATS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699} asc_queue_t;
3700
3701/*
3702 * Adv Library Request Structures
3703 *
3704 * The following two structures are used to process Wide Board requests.
3705 *
3706 * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
3707 * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
3708 * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
3709 * Mid-Level SCSI request structure.
3710 *
3711 * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
3712 * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
3713 * up to 255 scatter-gather elements may be used per request or
3714 * ADV_SCSI_REQ_Q.
3715 *
3716 * Both structures must be 32 byte aligned.
3717 */
3718typedef struct adv_sgblk {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003719 ADV_SG_BLOCK sg_block; /* Sgblock structure. */
3720 uchar align[32]; /* Sgblock structure padding. */
3721 struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722} adv_sgblk_t;
3723
3724typedef struct adv_req {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003725 ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
3726 uchar align[32]; /* Request structure padding. */
3727 struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */
3728 adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
3729 struct adv_req *next_reqp; /* Next Request Structure. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730} adv_req_t;
3731
3732/*
3733 * Structure allocated for each board.
3734 *
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06003735 * This structure is allocated by scsi_host_alloc() at the end
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 * of the 'Scsi_Host' structure starting at the 'hostdata'
3737 * field. It is guaranteed to be allocated from DMA-able memory.
3738 */
3739typedef struct asc_board {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003740 int id; /* Board Id */
3741 uint flags; /* Board flags */
3742 union {
3743 ASC_DVC_VAR asc_dvc_var; /* Narrow board */
3744 ADV_DVC_VAR adv_dvc_var; /* Wide board */
3745 } dvc_var;
3746 union {
3747 ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
3748 ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
3749 } dvc_cfg;
3750 ushort asc_n_io_port; /* Number I/O ports. */
3751 asc_queue_t active; /* Active command queue */
3752 asc_queue_t waiting; /* Waiting command queue */
3753 asc_queue_t done; /* Done command queue */
3754 ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
3755 struct scsi_device *device[ADV_MAX_TID + 1]; /* Mid-Level Scsi Device */
3756 ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */
3757 ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
3758 ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */
3759 union {
3760 ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
3761 ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */
3762 ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */
3763 ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
3764 } eep_config;
3765 ulong last_reset; /* Saved last reset time */
3766 spinlock_t lock; /* Board spinlock */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003767 /* /proc/scsi/advansys/[0...] */
3768 char *prtbuf; /* /proc print buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003770 struct asc_stats asc_stats; /* Board statistics */
3771#endif /* ADVANSYS_STATS */
3772 /*
3773 * The following fields are used only for Narrow Boards.
3774 */
3775 /* The following three structures must be in DMA-able memory. */
3776 ASC_SCSI_REQ_Q scsireqq;
3777 ASC_CAP_INFO cap_info;
3778 ASC_SCSI_INQUIRY inquiry;
3779 uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */
3780 /*
3781 * The following fields are used only for Wide Boards.
3782 */
3783 void __iomem *ioremap_addr; /* I/O Memory remap address. */
3784 ushort ioport; /* I/O Port address. */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -06003785 ADV_CARR_T *carrp; /* ADV_CARR_T memory block. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003786 adv_req_t *orig_reqp; /* adv_req_t memory block. */
3787 adv_req_t *adv_reqp; /* Request structures. */
3788 adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
3789 ushort bios_signature; /* BIOS Signature. */
3790 ushort bios_version; /* BIOS Version. */
3791 ushort bios_codeseg; /* BIOS Code Segment. */
3792 ushort bios_codelen; /* BIOS Code Segment Length. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793} asc_board_t;
3794
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795/* Number of boards detected in system. */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06003796static int asc_board_count;
3797
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798/* Overrun buffer used by all narrow boards. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003799static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800
3801/*
3802 * Global structures required to issue a command.
3803 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003804static ASC_SCSI_Q asc_scsi_q = { {0} };
3805static ASC_SG_HEAD asc_sg_head = { 0 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003808static int asc_dbglvl = 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809#endif /* ADVANSYS_DEBUG */
3810
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811/*
3812 * --- Driver Function Prototypes
3813 *
3814 * advansys.h contains function prototypes for functions global to Linux.
3815 */
3816
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003817static int advansys_slave_configure(struct scsi_device *);
3818static void asc_scsi_done_list(struct scsi_cmnd *);
3819static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
3820static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
3821static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
3822static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
3823static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
3824static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
3825static void adv_async_callback(ADV_DVC_VAR *, uchar);
3826static void asc_enqueue(asc_queue_t *, REQP, int);
3827static REQP asc_dequeue(asc_queue_t *, int);
3828static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
3829static int asc_rmqueue(asc_queue_t *, REQP);
3830static void asc_execute_queue(asc_queue_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003832static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
3833static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
3834static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
3835static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
3836static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
3837static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
3838static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
3839static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
3840static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
3841static int asc_prt_line(char *, int, char *fmt, ...);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842#endif /* CONFIG_PROC_FS */
3843
3844/* Declaration for Asc Library internal functions referenced by driver. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003845static int AscFindSignature(PortAddr);
3846static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847
3848/* Statistics function prototypes. */
3849#ifdef ADVANSYS_STATS
3850#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003851static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
3852static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853#endif /* CONFIG_PROC_FS */
3854#endif /* ADVANSYS_STATS */
3855
3856/* Debug function prototypes. */
3857#ifdef ADVANSYS_DEBUG
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003858static void asc_prt_scsi_host(struct Scsi_Host *);
3859static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
3860static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
3861static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
3862static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
3863static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
3864static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
3865static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
3866static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
3867static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
3868static void asc_prt_hex(char *f, uchar *, int);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869#endif /* ADVANSYS_DEBUG */
3870
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871#ifdef CONFIG_PROC_FS
3872/*
Matthew Wilcoxc304ec92007-07-30 09:18:45 -06003873 * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 *
3875 * *buffer: I/O buffer
3876 * **start: if inout == FALSE pointer into buffer where user read should start
3877 * offset: current offset into a /proc/scsi/advansys/[0...] file
3878 * length: length of buffer
3879 * hostno: Scsi_Host host_no
3880 * inout: TRUE - user is writing; FALSE - user is reading
3881 *
3882 * Return the number of bytes read from or written to a
3883 * /proc/scsi/advansys/[0...] file.
3884 *
3885 * Note: This function uses the per board buffer 'prtbuf' which is
3886 * allocated when the board is initialized in advansys_detect(). The
3887 * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
3888 * used to write to the buffer. The way asc_proc_copy() is written
3889 * if 'prtbuf' is too small it will not be overwritten. Instead the
3890 * user just won't get all the available statistics.
3891 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07003892static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003894 off_t offset, int length, int inout)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003896 asc_board_t *boardp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003897 char *cp;
3898 int cplen;
3899 int cnt;
3900 int totcnt;
3901 int leftlen;
3902 char *curbuf;
3903 off_t advoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003905 int tgt_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906#endif /* ADVANSYS_STATS */
3907
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003908 ASC_DBG(1, "advansys_proc_info: begin\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003910 /*
3911 * User write not supported.
3912 */
3913 if (inout == TRUE) {
3914 return (-ENOSYS);
3915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003917 /*
3918 * User read of /proc/scsi/advansys/[0...] file.
3919 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920
Matthew Wilcox2a437952007-07-26 11:00:51 -04003921 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003923 /* Copy read data starting at the beginning of the buffer. */
3924 *start = buffer;
3925 curbuf = buffer;
3926 advoffset = 0;
3927 totcnt = 0;
3928 leftlen = length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003930 /*
3931 * Get board configuration information.
3932 *
3933 * advansys_info() returns the board string from its own static buffer.
3934 */
Matthew Wilcox2a437952007-07-26 11:00:51 -04003935 cp = (char *)advansys_info(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003936 strcat(cp, "\n");
3937 cplen = strlen(cp);
3938 /* Copy board information. */
3939 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3940 totcnt += cnt;
3941 leftlen -= cnt;
3942 if (leftlen == 0) {
3943 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3944 return totcnt;
3945 }
3946 advoffset += cplen;
3947 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003949 /*
3950 * Display Wide Board BIOS Information.
3951 */
3952 if (ASC_WIDE_BOARD(boardp)) {
3953 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003954 cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003955 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3956 cnt =
3957 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
3958 cplen);
3959 totcnt += cnt;
3960 leftlen -= cnt;
3961 if (leftlen == 0) {
3962 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3963 return totcnt;
3964 }
3965 advoffset += cplen;
3966 curbuf += cnt;
3967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003969 /*
3970 * Display driver information for each device attached to the board.
3971 */
3972 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04003973 cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003974 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3975 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3976 totcnt += cnt;
3977 leftlen -= cnt;
3978 if (leftlen == 0) {
3979 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
3980 return totcnt;
3981 }
3982 advoffset += cplen;
3983 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003985 /*
3986 * Display EEPROM configuration for the board.
3987 */
3988 cp = boardp->prtbuf;
3989 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003990 cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003991 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04003992 cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04003993 }
3994 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
3995 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
3996 totcnt += cnt;
3997 leftlen -= cnt;
3998 if (leftlen == 0) {
3999 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4000 return totcnt;
4001 }
4002 advoffset += cplen;
4003 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004005 /*
4006 * Display driver configuration and information for the board.
4007 */
4008 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004009 cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004010 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4011 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4012 totcnt += cnt;
4013 leftlen -= cnt;
4014 if (leftlen == 0) {
4015 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4016 return totcnt;
4017 }
4018 advoffset += cplen;
4019 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020
4021#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004022 /*
4023 * Display driver statistics for the board.
4024 */
4025 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004026 cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004027 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4028 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4029 totcnt += cnt;
4030 leftlen -= cnt;
4031 if (leftlen == 0) {
4032 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4033 return totcnt;
4034 }
4035 advoffset += cplen;
4036 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004038 /*
4039 * Display driver statistics for each target.
4040 */
4041 for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
4042 cp = boardp->prtbuf;
Matthew Wilcox2a437952007-07-26 11:00:51 -04004043 cplen = asc_prt_target_stats(shost, tgt_id, cp,
4044 ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004045 ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
4046 cnt =
4047 asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
4048 cplen);
4049 totcnt += cnt;
4050 leftlen -= cnt;
4051 if (leftlen == 0) {
4052 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4053 return totcnt;
4054 }
4055 advoffset += cplen;
4056 curbuf += cnt;
4057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058#endif /* ADVANSYS_STATS */
4059
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004060 /*
4061 * Display Asc Library dynamic configuration information
4062 * for the board.
4063 */
4064 cp = boardp->prtbuf;
4065 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004066 cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004067 } else {
Matthew Wilcox2a437952007-07-26 11:00:51 -04004068 cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004069 }
4070 ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
4071 cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
4072 totcnt += cnt;
4073 leftlen -= cnt;
4074 if (leftlen == 0) {
4075 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
4076 return totcnt;
4077 }
4078 advoffset += cplen;
4079 curbuf += cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004081 ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004083 return totcnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084}
4085#endif /* CONFIG_PROC_FS */
4086
4087/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 * advansys_info()
4089 *
4090 * Return suitable for printing on the console with the argument
4091 * adapter's configuration information.
4092 *
4093 * Note: The information line should not exceed ASC_INFO_SIZE bytes,
4094 * otherwise the static 'info' array will be overrun.
4095 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004096static const char *advansys_info(struct Scsi_Host *shost)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004098 static char info[ASC_INFO_SIZE];
4099 asc_board_t *boardp;
4100 ASC_DVC_VAR *asc_dvc_varp;
4101 ADV_DVC_VAR *adv_dvc_varp;
4102 char *busname;
4103 int iolen;
4104 char *widename = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004106 boardp = ASC_BOARDP(shost);
4107 if (ASC_NARROW_BOARD(boardp)) {
4108 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
4109 ASC_DBG(1, "advansys_info: begin\n");
4110 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
4111 if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
4112 ASC_IS_ISAPNP) {
4113 busname = "ISA PnP";
4114 } else {
4115 busname = "ISA";
4116 }
4117 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4118 sprintf(info,
4119 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
4120 ASC_VERSION, busname,
4121 (ulong)shost->io_port,
4122 (ulong)shost->io_port + boardp->asc_n_io_port -
4123 1, shost->irq, shost->dma_channel);
4124 } else {
4125 if (asc_dvc_varp->bus_type & ASC_IS_VL) {
4126 busname = "VL";
4127 } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
4128 busname = "EISA";
4129 } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
4130 if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
4131 == ASC_IS_PCI_ULTRA) {
4132 busname = "PCI Ultra";
4133 } else {
4134 busname = "PCI";
4135 }
4136 } else {
4137 busname = "?";
4138 ASC_PRINT2
4139 ("advansys_info: board %d: unknown bus type %d\n",
4140 boardp->id, asc_dvc_varp->bus_type);
4141 }
4142 /* Don't reference 'shost->n_io_port'; It may be truncated. */
4143 sprintf(info,
4144 "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
4145 ASC_VERSION, busname,
4146 (ulong)shost->io_port,
4147 (ulong)shost->io_port + boardp->asc_n_io_port -
4148 1, shost->irq);
4149 }
4150 } else {
4151 /*
4152 * Wide Adapter Information
4153 *
4154 * Memory-mapped I/O is used instead of I/O space to access
4155 * the adapter, but display the I/O Port range. The Memory
4156 * I/O address is displayed through the driver /proc file.
4157 */
4158 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
4159 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
4160 iolen = ADV_3550_IOLEN;
4161 widename = "Ultra-Wide";
4162 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
4163 iolen = ADV_38C0800_IOLEN;
4164 widename = "Ultra2-Wide";
4165 } else {
4166 iolen = ADV_38C1600_IOLEN;
4167 widename = "Ultra3-Wide";
4168 }
4169 sprintf(info,
4170 "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
4171 ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
4172 (ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
4173 }
4174 ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
4175 ASC_DBG(1, "advansys_info: end\n");
4176 return info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177}
4178
4179/*
4180 * advansys_queuecommand() - interrupt-driven I/O entrypoint.
4181 *
4182 * This function always returns 0. Command return status is saved
4183 * in the 'scp' result field.
4184 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004185static int
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004186advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004188 struct Scsi_Host *shost;
4189 asc_board_t *boardp;
4190 ulong flags;
4191 struct scsi_cmnd *done_scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004193 shost = scp->device->host;
4194 boardp = ASC_BOARDP(shost);
4195 ASC_STATS(shost, queuecommand);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004197 /* host_lock taken by mid-level prior to call but need to protect */
4198 /* against own ISR */
4199 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004201 /*
4202 * Block new commands while handling a reset or abort request.
4203 */
4204 if (boardp->flags & ASC_HOST_IN_RESET) {
4205 ASC_DBG1(1,
4206 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
4207 (ulong)scp);
4208 scp->result = HOST_BYTE(DID_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004210 /*
4211 * Add blocked requests to the board's 'done' queue. The queued
4212 * requests will be completed at the end of the abort or reset
4213 * handling.
4214 */
4215 asc_enqueue(&boardp->done, scp, ASC_BACK);
4216 spin_unlock_irqrestore(&boardp->lock, flags);
4217 return 0;
4218 }
4219
4220 /*
4221 * Attempt to execute any waiting commands for the board.
4222 */
4223 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4224 ASC_DBG(1,
4225 "advansys_queuecommand: before asc_execute_queue() waiting\n");
4226 asc_execute_queue(&boardp->waiting);
4227 }
4228
4229 /*
4230 * Save the function pointer to Linux mid-level 'done' function
4231 * and attempt to execute the command.
4232 *
4233 * If ASC_NOERROR is returned the request has been added to the
4234 * board's 'active' queue and will be completed by the interrupt
4235 * handler.
4236 *
4237 * If ASC_BUSY is returned add the request to the board's per
4238 * target waiting list. This is the first time the request has
4239 * been tried. Add it to the back of the waiting list. It will be
4240 * retried later.
4241 *
4242 * If an error occurred, the request will have been placed on the
4243 * board's 'done' queue and must be completed before returning.
4244 */
4245 scp->scsi_done = done;
4246 switch (asc_execute_scsi_cmnd(scp)) {
4247 case ASC_NOERROR:
4248 break;
4249 case ASC_BUSY:
4250 asc_enqueue(&boardp->waiting, scp, ASC_BACK);
4251 break;
4252 case ASC_ERROR:
4253 default:
4254 done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
4255 /* Interrupts could be enabled here. */
4256 asc_scsi_done_list(done_scp);
4257 break;
4258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004261 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262}
4263
4264/*
4265 * advansys_reset()
4266 *
4267 * Reset the bus associated with the command 'scp'.
4268 *
4269 * This function runs its own thread. Interrupts must be blocked but
4270 * sleeping is allowed and no locking other than for host structures is
4271 * required. Returns SUCCESS or FAILED.
4272 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004273static int advansys_reset(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004275 struct Scsi_Host *shost;
4276 asc_board_t *boardp;
4277 ASC_DVC_VAR *asc_dvc_varp;
4278 ADV_DVC_VAR *adv_dvc_varp;
4279 ulong flags;
4280 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4281 struct scsi_cmnd *tscp, *new_last_scp;
4282 int status;
4283 int ret = SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004285 ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286
4287#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004288 if (scp->device->host != NULL) {
4289 ASC_STATS(scp->device->host, reset);
4290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291#endif /* ADVANSYS_STATS */
4292
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004293 if ((shost = scp->device->host) == NULL) {
4294 scp->result = HOST_BYTE(DID_ERROR);
4295 return FAILED;
4296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004298 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004300 ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
4301 boardp->id);
4302 /*
4303 * Check for re-entrancy.
4304 */
4305 spin_lock_irqsave(&boardp->lock, flags);
4306 if (boardp->flags & ASC_HOST_IN_RESET) {
4307 spin_unlock_irqrestore(&boardp->lock, flags);
4308 return FAILED;
4309 }
4310 boardp->flags |= ASC_HOST_IN_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004313 if (ASC_NARROW_BOARD(boardp)) {
4314 /*
4315 * Narrow Board
4316 */
4317 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004319 /*
4320 * Reset the chip and SCSI bus.
4321 */
4322 ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
4323 status = AscInitAsc1000Driver(asc_dvc_varp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004325 /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
4326 if (asc_dvc_varp->err_code) {
4327 ASC_PRINT2
4328 ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
4329 boardp->id, asc_dvc_varp->err_code);
4330 ret = FAILED;
4331 } else if (status) {
4332 ASC_PRINT2
4333 ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
4334 boardp->id, status);
4335 } else {
4336 ASC_PRINT1
4337 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4338 boardp->id);
4339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004341 ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
4342 spin_lock_irqsave(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004344 } else {
4345 /*
4346 * Wide Board
4347 *
4348 * If the suggest reset bus flags are set, then reset the bus.
4349 * Otherwise only reset the device.
4350 */
4351 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004353 /*
4354 * Reset the target's SCSI bus.
4355 */
4356 ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
4357 switch (AdvResetChipAndSB(adv_dvc_varp)) {
4358 case ASC_TRUE:
4359 ASC_PRINT1
4360 ("advansys_reset: board %d: SCSI bus reset successful.\n",
4361 boardp->id);
4362 break;
4363 case ASC_FALSE:
4364 default:
4365 ASC_PRINT1
4366 ("advansys_reset: board %d: SCSI bus reset error.\n",
4367 boardp->id);
4368 ret = FAILED;
4369 break;
4370 }
4371 spin_lock_irqsave(&boardp->lock, flags);
4372 (void)AdvISR(adv_dvc_varp);
4373 }
4374 /* Board lock is held. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004376 /*
4377 * Dequeue all board 'done' requests. A pointer to the last request
4378 * is returned in 'last_scp'.
4379 */
4380 done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004382 /*
4383 * Dequeue all board 'active' requests for all devices and set
4384 * the request status to DID_RESET. A pointer to the last request
4385 * is returned in 'last_scp'.
4386 */
4387 if (done_scp == NULL) {
4388 done_scp =
4389 asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
4390 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4391 tscp->result = HOST_BYTE(DID_RESET);
4392 }
4393 } else {
4394 /* Append to 'done_scp' at the end with 'last_scp'. */
4395 ASC_ASSERT(last_scp != NULL);
4396 last_scp->host_scribble =
4397 (unsigned char *)asc_dequeue_list(&boardp->active,
4398 &new_last_scp,
4399 ASC_TID_ALL);
4400 if (new_last_scp != NULL) {
4401 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4402 for (tscp = REQPNEXT(last_scp); tscp;
4403 tscp = REQPNEXT(tscp)) {
4404 tscp->result = HOST_BYTE(DID_RESET);
4405 }
4406 last_scp = new_last_scp;
4407 }
4408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004410 /*
4411 * Dequeue all 'waiting' requests and set the request status
4412 * to DID_RESET.
4413 */
4414 if (done_scp == NULL) {
4415 done_scp =
4416 asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
4417 for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
4418 tscp->result = HOST_BYTE(DID_RESET);
4419 }
4420 } else {
4421 /* Append to 'done_scp' at the end with 'last_scp'. */
4422 ASC_ASSERT(last_scp != NULL);
4423 last_scp->host_scribble =
4424 (unsigned char *)asc_dequeue_list(&boardp->waiting,
4425 &new_last_scp,
4426 ASC_TID_ALL);
4427 if (new_last_scp != NULL) {
4428 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4429 for (tscp = REQPNEXT(last_scp); tscp;
4430 tscp = REQPNEXT(tscp)) {
4431 tscp->result = HOST_BYTE(DID_RESET);
4432 }
4433 last_scp = new_last_scp;
4434 }
4435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004437 /* Save the time of the most recently completed reset. */
4438 boardp->last_reset = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004440 /* Clear reset flag. */
4441 boardp->flags &= ~ASC_HOST_IN_RESET;
4442 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004444 /*
4445 * Complete all the 'done_scp' requests.
4446 */
4447 if (done_scp != NULL) {
4448 asc_scsi_done_list(done_scp);
4449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004451 ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004453 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454}
4455
4456/*
4457 * advansys_biosparam()
4458 *
4459 * Translate disk drive geometry if the "BIOS greater than 1 GB"
4460 * support is enabled for a drive.
4461 *
4462 * ip (information pointer) is an int array with the following definition:
4463 * ip[0]: heads
4464 * ip[1]: sectors
4465 * ip[2]: cylinders
4466 */
Adrian Bunk70c8d892007-05-23 14:41:35 -07004467static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004469 sector_t capacity, int ip[])
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004471 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004473 ASC_DBG(1, "advansys_biosparam: begin\n");
4474 ASC_STATS(sdev->host, biosparam);
4475 boardp = ASC_BOARDP(sdev->host);
4476 if (ASC_NARROW_BOARD(boardp)) {
4477 if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
4478 ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
4479 ip[0] = 255;
4480 ip[1] = 63;
4481 } else {
4482 ip[0] = 64;
4483 ip[1] = 32;
4484 }
4485 } else {
4486 if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
4487 BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
4488 ip[0] = 255;
4489 ip[1] = 63;
4490 } else {
4491 ip[0] = 64;
4492 ip[1] = 32;
4493 }
4494 }
4495 ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
4496 ASC_DBG(1, "advansys_biosparam: end\n");
4497 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498}
4499
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004500static struct scsi_host_template advansys_template = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004501 .proc_name = "advansys",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502#ifdef CONFIG_PROC_FS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004503 .proc_info = advansys_proc_info,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504#endif
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004505 .name = "advansys",
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004506 .info = advansys_info,
4507 .queuecommand = advansys_queuecommand,
4508 .eh_bus_reset_handler = advansys_reset,
4509 .bios_param = advansys_biosparam,
4510 .slave_configure = advansys_slave_configure,
4511 /*
4512 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
Matthew Wilcox8dfb5372007-07-30 09:08:34 -06004513 * must be set. The flag will be cleared in advansys_board_found
4514 * for non-ISA adapters.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004515 */
4516 .unchecked_isa_dma = 1,
4517 /*
4518 * All adapters controlled by this driver are capable of large
4519 * scatter-gather lists. According to the mid-level SCSI documentation
4520 * this obviates any performance gain provided by setting
4521 * 'use_clustering'. But empirically while CPU utilization is increased
4522 * by enabling clustering, I/O throughput increases as well.
4523 */
4524 .use_clustering = ENABLE_CLUSTERING,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525};
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527/*
4528 * --- Miscellaneous Driver Functions
4529 */
4530
4531/*
4532 * First-level interrupt handler.
4533 *
4534 * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
4535 * all boards are currently checked for interrupts on each interrupt, 'dev_id'
4536 * is not referenced. 'dev_id' could be used to identify an interrupt passed
4537 * to the AdvanSys driver which is for a device sharing an interrupt with
4538 * an AdvanSys adapter.
4539 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004540static irqreturn_t advansys_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541{
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004542 unsigned long flags;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004543 struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
4544 struct scsi_cmnd *new_last_scp;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004545 struct Scsi_Host *shost = dev_id;
4546 asc_board_t *boardp = ASC_BOARDP(shost);
4547 irqreturn_t result = IRQ_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004549 ASC_DBG1(2, "advansys_interrupt: boardp 0x%p\n", boardp);
4550 spin_lock_irqsave(&boardp->lock, flags);
4551 if (ASC_NARROW_BOARD(boardp)) {
4552 /*
4553 * Narrow Board
4554 */
4555 if (AscIsIntPending(shost->io_port)) {
4556 result = IRQ_HANDLED;
4557 ASC_STATS(shost, interrupt);
4558 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
4559 AscISR(&boardp->dvc_var.asc_dvc_var);
4560 }
4561 } else {
4562 /*
4563 * Wide Board
4564 */
4565 ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
4566 if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
4567 result = IRQ_HANDLED;
4568 ASC_STATS(shost, interrupt);
4569 }
4570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004572 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004573 * Start waiting requests and create a list of completed requests.
4574 *
4575 * If a reset request is being performed for the board, the reset
4576 * handler will complete pending requests after it has completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004577 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004578 if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
4579 ASC_DBG2(1, "advansys_interrupt: done_scp 0x%p, "
4580 "last_scp 0x%p\n", done_scp, last_scp);
4581
4582 /* Start any waiting commands for the board. */
4583 if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
4584 ASC_DBG(1, "advansys_interrupt: before "
4585 "asc_execute_queue()\n");
4586 asc_execute_queue(&boardp->waiting);
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004589 /*
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004590 * Add to the list of requests that must be completed.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004591 *
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004592 * 'done_scp' will always be NULL on the first iteration of
4593 * this loop. 'last_scp' is set at the same time as 'done_scp'.
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004594 */
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004595 if (done_scp == NULL) {
4596 done_scp = asc_dequeue_list(&boardp->done,
4597 &last_scp, ASC_TID_ALL);
4598 } else {
4599 ASC_ASSERT(last_scp != NULL);
4600 last_scp->host_scribble =
4601 (unsigned char *)asc_dequeue_list(&boardp->
4602 done,
4603 &new_last_scp,
4604 ASC_TID_ALL);
4605 if (new_last_scp != NULL) {
4606 ASC_ASSERT(REQPNEXT(last_scp) != NULL);
4607 last_scp = new_last_scp;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004608 }
4609 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004610 }
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004611 spin_unlock_irqrestore(&boardp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004613 /*
4614 * If interrupts were enabled on entry, then they
4615 * are now enabled here.
4616 *
4617 * Complete all requests on the done list.
4618 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004620 asc_scsi_done_list(done_scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004622 ASC_DBG(1, "advansys_interrupt: end\n");
Matthew Wilcox074c8fe2007-07-28 23:11:05 -06004623 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624}
4625
4626/*
4627 * Set the number of commands to queue per device for the
4628 * specified host adapter.
4629 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004630static int advansys_slave_configure(struct scsi_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004632 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004634 boardp = ASC_BOARDP(device->host);
4635 boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
4636 /*
4637 * Save a pointer to the device and set its initial/maximum
4638 * queue depth. Only save the pointer for a lun0 dev though.
4639 */
4640 if (device->lun == 0)
4641 boardp->device[device->id] = device;
4642 if (device->tagged_supported) {
4643 if (ASC_NARROW_BOARD(boardp)) {
4644 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4645 boardp->dvc_var.asc_dvc_var.
4646 max_dvc_qng[device->id]);
4647 } else {
4648 scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
4649 boardp->dvc_var.adv_dvc_var.
4650 max_dvc_qng);
4651 }
4652 } else {
4653 scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
4654 }
4655 ASC_DBG4(1,
4656 "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
4657 (ulong)device, (ulong)boardp, device->id, device->queue_depth);
4658 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659}
4660
4661/*
4662 * Complete all requests on the singly linked list pointed
4663 * to by 'scp'.
4664 *
4665 * Interrupts can be enabled on entry.
4666 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004667static void asc_scsi_done_list(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004669 struct scsi_cmnd *tscp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004671 ASC_DBG(2, "asc_scsi_done_list: begin\n");
4672 while (scp != NULL) {
4673 asc_board_t *boardp;
4674 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004676 ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
4677 tscp = REQPNEXT(scp);
4678 scp->host_scribble = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004680 boardp = ASC_BOARDP(scp->device->host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004682 if (ASC_NARROW_BOARD(boardp))
4683 dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
4684 else
4685 dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004687 if (scp->use_sg)
4688 dma_unmap_sg(dev,
4689 (struct scatterlist *)scp->request_buffer,
4690 scp->use_sg, scp->sc_data_direction);
4691 else if (scp->request_bufflen)
4692 dma_unmap_single(dev, scp->SCp.dma_handle,
4693 scp->request_bufflen,
4694 scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004696 ASC_STATS(scp->device->host, done);
4697 ASC_ASSERT(scp->scsi_done != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004699 scp->scsi_done(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004701 scp = tscp;
4702 }
4703 ASC_DBG(2, "asc_scsi_done_list: done\n");
4704 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705}
4706
4707/*
4708 * Execute a single 'Scsi_Cmnd'.
4709 *
4710 * The function 'done' is called when the request has been completed.
4711 *
4712 * Scsi_Cmnd:
4713 *
4714 * host - board controlling device
4715 * device - device to send command
4716 * target - target of device
4717 * lun - lun of device
4718 * cmd_len - length of SCSI CDB
4719 * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
4720 * use_sg - if non-zero indicates scatter-gather request with use_sg elements
4721 *
4722 * if (use_sg == 0) {
4723 * request_buffer - buffer address for request
4724 * request_bufflen - length of request buffer
4725 * } else {
4726 * request_buffer - pointer to scatterlist structure
4727 * }
4728 *
4729 * sense_buffer - sense command buffer
4730 *
4731 * result (4 bytes of an int):
4732 * Byte Meaning
4733 * 0 SCSI Status Byte Code
4734 * 1 SCSI One Byte Message Code
4735 * 2 Host Error Code
4736 * 3 Mid-Level Error Code
4737 *
4738 * host driver fields:
4739 * SCp - Scsi_Pointer used for command processing status
4740 * scsi_done - used to save caller's done function
4741 * host_scribble - used for pointer to another struct scsi_cmnd
4742 *
4743 * If this function returns ASC_NOERROR the request has been enqueued
4744 * on the board's 'active' queue and will be completed from the
4745 * interrupt handler.
4746 *
4747 * If this function returns ASC_NOERROR the request has been enqueued
4748 * on the board's 'done' queue and must be completed by the caller.
4749 *
4750 * If ASC_BUSY is returned the request will be enqueued by the
4751 * caller on the target's waiting queue and re-tried later.
4752 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004753static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004755 asc_board_t *boardp;
4756 ASC_DVC_VAR *asc_dvc_varp;
4757 ADV_DVC_VAR *adv_dvc_varp;
4758 ADV_SCSI_REQ_Q *adv_scsiqp;
4759 struct scsi_device *device;
4760 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004762 ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
4763 (ulong)scp, (ulong)scp->scsi_done);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004765 boardp = ASC_BOARDP(scp->device->host);
4766 device = boardp->device[scp->device->id];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004768 if (ASC_NARROW_BOARD(boardp)) {
4769 /*
4770 * Build and execute Narrow Board request.
4771 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004773 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004775 /*
4776 * Build Asc Library request structure using the
4777 * global structures 'asc_scsi_req' and 'asc_sg_head'.
4778 *
4779 * If an error is returned, then the request has been
4780 * queued on the board done queue. It will be completed
4781 * by the caller.
4782 *
4783 * asc_build_req() can not return ASC_BUSY.
4784 */
4785 if (asc_build_req(boardp, scp) == ASC_ERROR) {
4786 ASC_STATS(scp->device->host, build_error);
4787 return ASC_ERROR;
4788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004790 /*
4791 * Execute the command. If there is no error, add the command
4792 * to the active queue.
4793 */
4794 switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
4795 case ASC_NOERROR:
4796 ASC_STATS(scp->device->host, exe_noerror);
4797 /*
4798 * Increment monotonically increasing per device successful
4799 * request counter. Wrapping doesn't matter.
4800 */
4801 boardp->reqcnt[scp->device->id]++;
4802 asc_enqueue(&boardp->active, scp, ASC_BACK);
4803 ASC_DBG(1,
4804 "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
4805 break;
4806 case ASC_BUSY:
4807 /*
4808 * Caller will enqueue request on the target's waiting queue
4809 * and retry later.
4810 */
4811 ASC_STATS(scp->device->host, exe_busy);
4812 break;
4813 case ASC_ERROR:
4814 ASC_PRINT2
4815 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4816 boardp->id, asc_dvc_varp->err_code);
4817 ASC_STATS(scp->device->host, exe_error);
4818 scp->result = HOST_BYTE(DID_ERROR);
4819 asc_enqueue(&boardp->done, scp, ASC_BACK);
4820 break;
4821 default:
4822 ASC_PRINT2
4823 ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
4824 boardp->id, asc_dvc_varp->err_code);
4825 ASC_STATS(scp->device->host, exe_unknown);
4826 scp->result = HOST_BYTE(DID_ERROR);
4827 asc_enqueue(&boardp->done, scp, ASC_BACK);
4828 break;
4829 }
4830 } else {
4831 /*
4832 * Build and execute Wide Board request.
4833 */
4834 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004836 /*
4837 * Build and get a pointer to an Adv Library request structure.
4838 *
4839 * If the request is successfully built then send it below,
4840 * otherwise return with an error.
4841 */
4842 switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
4843 case ASC_NOERROR:
4844 ASC_DBG(3,
4845 "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
4846 break;
4847 case ASC_BUSY:
4848 ASC_DBG(1,
4849 "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
4850 /*
4851 * If busy is returned the request has not been enqueued.
4852 * It will be enqueued by the caller on the target's waiting
4853 * queue and retried later.
4854 *
4855 * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
4856 * count wide board busy conditions. They are updated in
4857 * adv_build_req and adv_get_sglist, respectively.
4858 */
4859 return ASC_BUSY;
4860 case ASC_ERROR:
4861 /*
4862 * If an error is returned, then the request has been
4863 * queued on the board done queue. It will be completed
4864 * by the caller.
4865 */
4866 default:
4867 ASC_DBG(1,
4868 "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
4869 ASC_STATS(scp->device->host, build_error);
4870 return ASC_ERROR;
4871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004873 /*
4874 * Execute the command. If there is no error, add the command
4875 * to the active queue.
4876 */
4877 switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
4878 case ASC_NOERROR:
4879 ASC_STATS(scp->device->host, exe_noerror);
4880 /*
4881 * Increment monotonically increasing per device successful
4882 * request counter. Wrapping doesn't matter.
4883 */
4884 boardp->reqcnt[scp->device->id]++;
4885 asc_enqueue(&boardp->active, scp, ASC_BACK);
4886 ASC_DBG(1,
4887 "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
4888 break;
4889 case ASC_BUSY:
4890 /*
4891 * Caller will enqueue request on the target's waiting queue
4892 * and retry later.
4893 */
4894 ASC_STATS(scp->device->host, exe_busy);
4895 break;
4896 case ASC_ERROR:
4897 ASC_PRINT2
4898 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
4899 boardp->id, adv_dvc_varp->err_code);
4900 ASC_STATS(scp->device->host, exe_error);
4901 scp->result = HOST_BYTE(DID_ERROR);
4902 asc_enqueue(&boardp->done, scp, ASC_BACK);
4903 break;
4904 default:
4905 ASC_PRINT2
4906 ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
4907 boardp->id, adv_dvc_varp->err_code);
4908 ASC_STATS(scp->device->host, exe_unknown);
4909 scp->result = HOST_BYTE(DID_ERROR);
4910 asc_enqueue(&boardp->done, scp, ASC_BACK);
4911 break;
4912 }
4913 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004915 ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
4916 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917}
4918
4919/*
4920 * Build a request structure for the Asc Library (Narrow Board).
4921 *
4922 * The global structures 'asc_scsi_q' and 'asc_sg_head' are
4923 * used to build the request.
4924 *
4925 * If an error occurs, then queue the request on the board done
4926 * queue and return ASC_ERROR.
4927 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004928static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004930 struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004932 /*
4933 * Mutually exclusive access is required to 'asc_scsi_q' and
4934 * 'asc_sg_head' until after the request is started.
4935 */
4936 memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004938 /*
4939 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
4940 */
4941 asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004943 /*
4944 * Build the ASC_SCSI_Q request.
4945 *
4946 * For narrow boards a CDB length maximum of 12 bytes
4947 * is supported.
4948 */
4949 if (scp->cmd_len > ASC_MAX_CDB_LEN) {
4950 ASC_PRINT3
4951 ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN %d\n",
4952 boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
4953 scp->result = HOST_BYTE(DID_ERROR);
4954 asc_enqueue(&boardp->done, scp, ASC_BACK);
4955 return ASC_ERROR;
4956 }
4957 asc_scsi_q.cdbptr = &scp->cmnd[0];
4958 asc_scsi_q.q2.cdb_len = scp->cmd_len;
4959 asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
4960 asc_scsi_q.q1.target_lun = scp->device->lun;
4961 asc_scsi_q.q2.target_ix =
4962 ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
4963 asc_scsi_q.q1.sense_addr =
4964 cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
4965 asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004967 /*
4968 * If there are any outstanding requests for the current target,
4969 * then every 255th request send an ORDERED request. This heuristic
4970 * tries to retain the benefit of request sorting while preventing
4971 * request starvation. 255 is the max number of tags or pending commands
4972 * a device may have outstanding.
4973 *
4974 * The request count is incremented below for every successfully
4975 * started request.
4976 *
4977 */
4978 if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
4979 (boardp->reqcnt[scp->device->id] % 255) == 0) {
4980 asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
4981 } else {
4982 asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
4983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984
Matthew Wilcox27c868c2007-07-26 10:56:23 -04004985 /*
4986 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
4987 * buffer command.
4988 */
4989 if (scp->use_sg == 0) {
4990 /*
4991 * CDB request of single contiguous buffer.
4992 */
4993 ASC_STATS(scp->device->host, cont_cnt);
4994 scp->SCp.dma_handle = scp->request_bufflen ?
4995 dma_map_single(dev, scp->request_buffer,
4996 scp->request_bufflen,
4997 scp->sc_data_direction) : 0;
4998 asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
4999 asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
5000 ASC_STATS_ADD(scp->device->host, cont_xfer,
5001 ASC_CEILING(scp->request_bufflen, 512));
5002 asc_scsi_q.q1.sg_queue_cnt = 0;
5003 asc_scsi_q.sg_head = NULL;
5004 } else {
5005 /*
5006 * CDB scatter-gather request list.
5007 */
5008 int sgcnt;
5009 int use_sg;
5010 struct scatterlist *slp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005012 slp = (struct scatterlist *)scp->request_buffer;
5013 use_sg =
5014 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005016 if (use_sg > scp->device->host->sg_tablesize) {
5017 ASC_PRINT3
5018 ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
5019 boardp->id, use_sg,
5020 scp->device->host->sg_tablesize);
5021 dma_unmap_sg(dev, slp, scp->use_sg,
5022 scp->sc_data_direction);
5023 scp->result = HOST_BYTE(DID_ERROR);
5024 asc_enqueue(&boardp->done, scp, ASC_BACK);
5025 return ASC_ERROR;
5026 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005027
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005028 ASC_STATS(scp->device->host, sg_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005030 /*
5031 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
5032 * structure to point to it.
5033 */
5034 memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005036 asc_scsi_q.q1.cntl |= QC_SG_HEAD;
5037 asc_scsi_q.sg_head = &asc_sg_head;
5038 asc_scsi_q.q1.data_cnt = 0;
5039 asc_scsi_q.q1.data_addr = 0;
5040 /* This is a byte value, otherwise it would need to be swapped. */
5041 asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
5042 ASC_STATS_ADD(scp->device->host, sg_elem,
5043 asc_sg_head.entry_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005045 /*
5046 * Convert scatter-gather list into ASC_SG_HEAD list.
5047 */
5048 for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
5049 asc_sg_head.sg_list[sgcnt].addr =
5050 cpu_to_le32(sg_dma_address(slp));
5051 asc_sg_head.sg_list[sgcnt].bytes =
5052 cpu_to_le32(sg_dma_len(slp));
5053 ASC_STATS_ADD(scp->device->host, sg_xfer,
5054 ASC_CEILING(sg_dma_len(slp), 512));
5055 }
5056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005058 ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
5059 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005061 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062}
5063
5064/*
5065 * Build a request structure for the Adv Library (Wide Board).
5066 *
5067 * If an adv_req_t can not be allocated to issue the request,
5068 * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
5069 *
5070 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
5071 * microcode for DMA addresses or math operations are byte swapped
5072 * to little-endian order.
5073 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005074static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07005075adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005076 ADV_SCSI_REQ_Q **adv_scsiqpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005078 adv_req_t *reqp;
5079 ADV_SCSI_REQ_Q *scsiqp;
5080 int i;
5081 int ret;
5082 struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005084 /*
5085 * Allocate an adv_req_t structure from the board to execute
5086 * the command.
5087 */
5088 if (boardp->adv_reqp == NULL) {
5089 ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
5090 ASC_STATS(scp->device->host, adv_build_noreq);
5091 return ASC_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092 } else {
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005093 reqp = boardp->adv_reqp;
5094 boardp->adv_reqp = reqp->next_reqp;
5095 reqp->next_reqp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005098 /*
5099 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
5100 */
5101 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005103 /*
5104 * Initialize the structure.
5105 */
5106 scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005108 /*
5109 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
5110 */
5111 scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005113 /*
5114 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
5115 */
5116 reqp->cmndp = scp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005118 /*
5119 * Build the ADV_SCSI_REQ_Q request.
5120 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005122 /*
5123 * Set CDB length and copy it to the request structure.
5124 * For wide boards a CDB length maximum of 16 bytes
5125 * is supported.
5126 */
5127 if (scp->cmd_len > ADV_MAX_CDB_LEN) {
5128 ASC_PRINT3
5129 ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN %d\n",
5130 boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
5131 scp->result = HOST_BYTE(DID_ERROR);
5132 asc_enqueue(&boardp->done, scp, ASC_BACK);
5133 return ASC_ERROR;
5134 }
5135 scsiqp->cdb_len = scp->cmd_len;
5136 /* Copy first 12 CDB bytes to cdb[]. */
5137 for (i = 0; i < scp->cmd_len && i < 12; i++) {
5138 scsiqp->cdb[i] = scp->cmnd[i];
5139 }
5140 /* Copy last 4 CDB bytes, if present, to cdb16[]. */
5141 for (; i < scp->cmd_len; i++) {
5142 scsiqp->cdb16[i - 12] = scp->cmnd[i];
5143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005145 scsiqp->target_id = scp->device->id;
5146 scsiqp->target_lun = scp->device->lun;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005148 scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
5149 scsiqp->sense_len = sizeof(scp->sense_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005151 /*
5152 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
5153 * buffer command.
5154 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005156 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5157 scsiqp->vdata_addr = scp->request_buffer;
5158 scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
5159
5160 if (scp->use_sg == 0) {
5161 /*
5162 * CDB request of single contiguous buffer.
5163 */
5164 reqp->sgblkp = NULL;
5165 scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
5166 if (scp->request_bufflen) {
5167 scsiqp->vdata_addr = scp->request_buffer;
5168 scp->SCp.dma_handle =
5169 dma_map_single(dev, scp->request_buffer,
5170 scp->request_bufflen,
5171 scp->sc_data_direction);
5172 } else {
5173 scsiqp->vdata_addr = NULL;
5174 scp->SCp.dma_handle = 0;
5175 }
5176 scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
5177 scsiqp->sg_list_ptr = NULL;
5178 scsiqp->sg_real_addr = 0;
5179 ASC_STATS(scp->device->host, cont_cnt);
5180 ASC_STATS_ADD(scp->device->host, cont_xfer,
5181 ASC_CEILING(scp->request_bufflen, 512));
5182 } else {
5183 /*
5184 * CDB scatter-gather request list.
5185 */
5186 struct scatterlist *slp;
5187 int use_sg;
5188
5189 slp = (struct scatterlist *)scp->request_buffer;
5190 use_sg =
5191 dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
5192
5193 if (use_sg > ADV_MAX_SG_LIST) {
5194 ASC_PRINT3
5195 ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
5196 boardp->id, use_sg,
5197 scp->device->host->sg_tablesize);
5198 dma_unmap_sg(dev, slp, scp->use_sg,
5199 scp->sc_data_direction);
5200 scp->result = HOST_BYTE(DID_ERROR);
5201 asc_enqueue(&boardp->done, scp, ASC_BACK);
5202
5203 /*
5204 * Free the 'adv_req_t' structure by adding it back to the
5205 * board free list.
5206 */
5207 reqp->next_reqp = boardp->adv_reqp;
5208 boardp->adv_reqp = reqp;
5209
5210 return ASC_ERROR;
5211 }
5212
5213 if ((ret =
5214 adv_get_sglist(boardp, reqp, scp,
5215 use_sg)) != ADV_SUCCESS) {
5216 /*
5217 * Free the adv_req_t structure by adding it back to the
5218 * board free list.
5219 */
5220 reqp->next_reqp = boardp->adv_reqp;
5221 boardp->adv_reqp = reqp;
5222
5223 return ret;
5224 }
5225
5226 ASC_STATS(scp->device->host, sg_cnt);
5227 ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
5228 }
5229
5230 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
5231 ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
5232
5233 *adv_scsiqpp = scsiqp;
5234
5235 return ASC_NOERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005236}
5237
5238/*
5239 * Build scatter-gather list for Adv Library (Wide Board).
5240 *
5241 * Additional ADV_SG_BLOCK structures will need to be allocated
5242 * if the total number of scatter-gather elements exceeds
5243 * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
5244 * assumed to be physically contiguous.
5245 *
5246 * Return:
5247 * ADV_SUCCESS(1) - SG List successfully created
5248 * ADV_ERROR(-1) - SG List creation failed
5249 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005250static int
5251adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
5252 int use_sg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005254 adv_sgblk_t *sgblkp;
5255 ADV_SCSI_REQ_Q *scsiqp;
5256 struct scatterlist *slp;
5257 int sg_elem_cnt;
5258 ADV_SG_BLOCK *sg_block, *prev_sg_block;
5259 ADV_PADDR sg_block_paddr;
5260 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005262 scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
5263 slp = (struct scatterlist *)scp->request_buffer;
5264 sg_elem_cnt = use_sg;
5265 prev_sg_block = NULL;
5266 reqp->sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005268 do {
5269 /*
5270 * Allocate a 'adv_sgblk_t' structure from the board free
5271 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
5272 * (15) scatter-gather elements.
5273 */
5274 if ((sgblkp = boardp->adv_sgblkp) == NULL) {
5275 ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
5276 ASC_STATS(scp->device->host, adv_build_nosg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005278 /*
5279 * Allocation failed. Free 'adv_sgblk_t' structures already
5280 * allocated for the request.
5281 */
5282 while ((sgblkp = reqp->sgblkp) != NULL) {
5283 /* Remove 'sgblkp' from the request list. */
5284 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005286 /* Add 'sgblkp' to the board free list. */
5287 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5288 boardp->adv_sgblkp = sgblkp;
5289 }
5290 return ASC_BUSY;
5291 } else {
5292 /* Complete 'adv_sgblk_t' board allocation. */
5293 boardp->adv_sgblkp = sgblkp->next_sgblkp;
5294 sgblkp->next_sgblkp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005296 /*
5297 * Get 8 byte aligned virtual and physical addresses for
5298 * the allocated ADV_SG_BLOCK structure.
5299 */
5300 sg_block =
5301 (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
5302 sg_block_paddr = virt_to_bus(sg_block);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005303
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005304 /*
5305 * Check if this is the first 'adv_sgblk_t' for the request.
5306 */
5307 if (reqp->sgblkp == NULL) {
5308 /* Request's first scatter-gather block. */
5309 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005311 /*
5312 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
5313 * address pointers.
5314 */
5315 scsiqp->sg_list_ptr = sg_block;
5316 scsiqp->sg_real_addr =
5317 cpu_to_le32(sg_block_paddr);
5318 } else {
5319 /* Request's second or later scatter-gather block. */
5320 sgblkp->next_sgblkp = reqp->sgblkp;
5321 reqp->sgblkp = sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005323 /*
5324 * Point the previous ADV_SG_BLOCK structure to
5325 * the newly allocated ADV_SG_BLOCK structure.
5326 */
5327 ASC_ASSERT(prev_sg_block != NULL);
5328 prev_sg_block->sg_ptr =
5329 cpu_to_le32(sg_block_paddr);
5330 }
5331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005333 for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
5334 sg_block->sg_list[i].sg_addr =
5335 cpu_to_le32(sg_dma_address(slp));
5336 sg_block->sg_list[i].sg_count =
5337 cpu_to_le32(sg_dma_len(slp));
5338 ASC_STATS_ADD(scp->device->host, sg_xfer,
5339 ASC_CEILING(sg_dma_len(slp), 512));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005341 if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */
5342 sg_block->sg_cnt = i + 1;
5343 sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */
5344 return ADV_SUCCESS;
5345 }
5346 slp++;
5347 }
5348 sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
5349 prev_sg_block = sg_block;
5350 }
5351 while (1);
5352 /* NOTREACHED */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353}
5354
5355/*
5356 * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
5357 *
5358 * Interrupt callback function for the Narrow SCSI Asc Library.
5359 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005360static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005362 asc_board_t *boardp;
5363 struct scsi_cmnd *scp;
5364 struct Scsi_Host *shost;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005366 ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
5367 (ulong)asc_dvc_varp, (ulong)qdonep);
5368 ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005370 /*
5371 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5372 * command that has been completed.
5373 */
5374 scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
5375 ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005377 if (scp == NULL) {
5378 ASC_PRINT("asc_isr_callback: scp is NULL\n");
5379 return;
5380 }
5381 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005383 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005384 ASC_STATS(shost, callback);
5385 ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005387 /*
5388 * If the request isn't found on the active queue, it may
5389 * have been removed to handle a reset request.
5390 * Display a message and return.
5391 */
5392 boardp = ASC_BOARDP(shost);
5393 ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
5394 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5395 ASC_PRINT2
5396 ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
5397 boardp->id, (ulong)scp);
5398 return;
5399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005401 /*
5402 * 'qdonep' contains the command's ending status.
5403 */
5404 switch (qdonep->d3.done_stat) {
5405 case QD_NO_ERROR:
5406 ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
5407 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005409 /*
5410 * If an INQUIRY command completed successfully, then call
5411 * the AscInquiryHandling() function to set-up the device.
5412 */
5413 if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
5414 (scp->request_bufflen - qdonep->remain_bytes) >= 8) {
5415 AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
5416 (ASC_SCSI_INQUIRY *)scp->
5417 request_buffer);
5418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005420 /*
5421 * Check for an underrun condition.
5422 *
5423 * If there was no error and an underrun condition, then
5424 * then return the number of underrun bytes.
5425 */
5426 if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
5427 qdonep->remain_bytes <= scp->request_bufflen) {
5428 ASC_DBG1(1,
5429 "asc_isr_callback: underrun condition %u bytes\n",
5430 (unsigned)qdonep->remain_bytes);
5431 scp->resid = qdonep->remain_bytes;
5432 }
5433 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005435 case QD_WITH_ERROR:
5436 ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
5437 switch (qdonep->d3.host_stat) {
5438 case QHSTA_NO_ERROR:
5439 if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
5440 ASC_DBG(2,
5441 "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5442 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5443 sizeof(scp->sense_buffer));
5444 /*
5445 * Note: The 'status_byte()' macro used by target drivers
5446 * defined in scsi.h shifts the status byte returned by
5447 * host drivers right by 1 bit. This is why target drivers
5448 * also use right shifted status byte definitions. For
5449 * instance target drivers use CHECK_CONDITION, defined to
5450 * 0x1, instead of the SCSI defined check condition value
5451 * of 0x2. Host drivers are supposed to return the status
5452 * byte as it is defined by SCSI.
5453 */
5454 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5455 STATUS_BYTE(qdonep->d3.scsi_stat);
5456 } else {
5457 scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
5458 }
5459 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005461 default:
5462 /* QHSTA error occurred */
5463 ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
5464 qdonep->d3.host_stat);
5465 scp->result = HOST_BYTE(DID_BAD_TARGET);
5466 break;
5467 }
5468 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005470 case QD_ABORTED_BY_HOST:
5471 ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
5472 scp->result =
5473 HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
5474 scsi_msg) |
5475 STATUS_BYTE(qdonep->d3.scsi_stat);
5476 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005478 default:
5479 ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
5480 qdonep->d3.done_stat);
5481 scp->result =
5482 HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
5483 scsi_msg) |
5484 STATUS_BYTE(qdonep->d3.scsi_stat);
5485 break;
5486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005488 /*
5489 * If the 'init_tidmask' bit isn't already set for the target and the
5490 * current request finished normally, then set the bit for the target
5491 * to indicate that a device is present.
5492 */
5493 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5494 qdonep->d3.done_stat == QD_NO_ERROR &&
5495 qdonep->d3.host_stat == QHSTA_NO_ERROR) {
5496 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5497 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005499 /*
5500 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5501 * function, add the command to the end of the board's done queue.
5502 * The done function for the command will be called from
5503 * advansys_interrupt().
5504 */
5505 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005507 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508}
5509
5510/*
5511 * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
5512 *
5513 * Callback function for the Wide SCSI Adv Library.
5514 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005515static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005516{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005517 asc_board_t *boardp;
5518 adv_req_t *reqp;
5519 adv_sgblk_t *sgblkp;
5520 struct scsi_cmnd *scp;
5521 struct Scsi_Host *shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005522 ADV_DCNT resid_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005524 ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
5525 (ulong)adv_dvc_varp, (ulong)scsiqp);
5526 ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005528 /*
5529 * Get the adv_req_t structure for the command that has been
5530 * completed. The adv_req_t structure actually contains the
5531 * completed ADV_SCSI_REQ_Q structure.
5532 */
5533 reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
5534 ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
5535 if (reqp == NULL) {
5536 ASC_PRINT("adv_isr_callback: reqp is NULL\n");
5537 return;
5538 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005539
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005540 /*
5541 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
5542 * command that has been completed.
5543 *
5544 * Note: The adv_req_t request structure and adv_sgblk_t structure,
5545 * if any, are dropped, because a board structure pointer can not be
5546 * determined.
5547 */
5548 scp = reqp->cmndp;
5549 ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
5550 if (scp == NULL) {
5551 ASC_PRINT
5552 ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
5553 return;
5554 }
5555 ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005557 shost = scp->device->host;
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005558 ASC_STATS(shost, callback);
5559 ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005560
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005561 /*
5562 * If the request isn't found on the active queue, it may have been
5563 * removed to handle a reset request. Display a message and return.
5564 *
5565 * Note: Because the structure may still be in use don't attempt
5566 * to free the adv_req_t and adv_sgblk_t, if any, structures.
5567 */
5568 boardp = ASC_BOARDP(shost);
5569 ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
5570 if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
5571 ASC_PRINT2
5572 ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
5573 boardp->id, (ulong)scp);
5574 return;
5575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005577 /*
5578 * 'done_status' contains the command's ending status.
5579 */
5580 switch (scsiqp->done_status) {
5581 case QD_NO_ERROR:
5582 ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
5583 scp->result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005585 /*
5586 * Check for an underrun condition.
5587 *
5588 * If there was no error and an underrun condition, then
5589 * then return the number of underrun bytes.
5590 */
5591 resid_cnt = le32_to_cpu(scsiqp->data_cnt);
5592 if (scp->request_bufflen != 0 && resid_cnt != 0 &&
5593 resid_cnt <= scp->request_bufflen) {
5594 ASC_DBG1(1,
5595 "adv_isr_callback: underrun condition %lu bytes\n",
5596 (ulong)resid_cnt);
5597 scp->resid = resid_cnt;
5598 }
5599 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005601 case QD_WITH_ERROR:
5602 ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
5603 switch (scsiqp->host_status) {
5604 case QHSTA_NO_ERROR:
5605 if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
5606 ASC_DBG(2,
5607 "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
5608 ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
5609 sizeof(scp->sense_buffer));
5610 /*
5611 * Note: The 'status_byte()' macro used by target drivers
5612 * defined in scsi.h shifts the status byte returned by
5613 * host drivers right by 1 bit. This is why target drivers
5614 * also use right shifted status byte definitions. For
5615 * instance target drivers use CHECK_CONDITION, defined to
5616 * 0x1, instead of the SCSI defined check condition value
5617 * of 0x2. Host drivers are supposed to return the status
5618 * byte as it is defined by SCSI.
5619 */
5620 scp->result = DRIVER_BYTE(DRIVER_SENSE) |
5621 STATUS_BYTE(scsiqp->scsi_status);
5622 } else {
5623 scp->result = STATUS_BYTE(scsiqp->scsi_status);
5624 }
5625 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005627 default:
5628 /* Some other QHSTA error occurred. */
5629 ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
5630 scsiqp->host_status);
5631 scp->result = HOST_BYTE(DID_BAD_TARGET);
5632 break;
5633 }
5634 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005636 case QD_ABORTED_BY_HOST:
5637 ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
5638 scp->result =
5639 HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
5640 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005642 default:
5643 ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
5644 scsiqp->done_status);
5645 scp->result =
5646 HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
5647 break;
5648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005650 /*
5651 * If the 'init_tidmask' bit isn't already set for the target and the
5652 * current request finished normally, then set the bit for the target
5653 * to indicate that a device is present.
5654 */
5655 if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
5656 scsiqp->done_status == QD_NO_ERROR &&
5657 scsiqp->host_status == QHSTA_NO_ERROR) {
5658 boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
5659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005661 /*
5662 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
5663 * function, add the command to the end of the board's done queue.
5664 * The done function for the command will be called from
5665 * advansys_interrupt().
5666 */
5667 asc_enqueue(&boardp->done, scp, ASC_BACK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005669 /*
5670 * Free all 'adv_sgblk_t' structures allocated for the request.
5671 */
5672 while ((sgblkp = reqp->sgblkp) != NULL) {
5673 /* Remove 'sgblkp' from the request list. */
5674 reqp->sgblkp = sgblkp->next_sgblkp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005676 /* Add 'sgblkp' to the board free list. */
5677 sgblkp->next_sgblkp = boardp->adv_sgblkp;
5678 boardp->adv_sgblkp = sgblkp;
5679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005681 /*
5682 * Free the adv_req_t structure used with the command by adding
5683 * it back to the board free list.
5684 */
5685 reqp->next_reqp = boardp->adv_reqp;
5686 boardp->adv_reqp = reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005688 ASC_DBG(1, "adv_isr_callback: done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005690 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691}
5692
5693/*
5694 * adv_async_callback() - Adv Library asynchronous event callback function.
5695 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005696static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005698 switch (code) {
5699 case ADV_ASYNC_SCSI_BUS_RESET_DET:
5700 /*
5701 * The firmware detected a SCSI Bus reset.
5702 */
5703 ASC_DBG(0,
5704 "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
5705 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005707 case ADV_ASYNC_RDMA_FAILURE:
5708 /*
5709 * Handle RDMA failure by resetting the SCSI Bus and
5710 * possibly the chip if it is unresponsive. Log the error
5711 * with a unique code.
5712 */
5713 ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
5714 AdvResetChipAndSB(adv_dvc_varp);
5715 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005717 case ADV_HOST_SCSI_BUS_RESET:
5718 /*
5719 * Host generated SCSI bus reset occurred.
5720 */
5721 ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
5722 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005724 default:
5725 ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
5726 break;
5727 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728}
5729
5730/*
5731 * Add a 'REQP' to the end of specified queue. Set 'tidmask'
5732 * to indicate a command is queued for the device.
5733 *
5734 * 'flag' may be either ASC_FRONT or ASC_BACK.
5735 *
5736 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5737 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005738static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005740 int tid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005742 ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
5743 (ulong)ascq, (ulong)reqp, flag);
5744 ASC_ASSERT(reqp != NULL);
5745 ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
5746 tid = REQPTID(reqp);
5747 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5748 if (flag == ASC_FRONT) {
5749 reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
5750 ascq->q_first[tid] = reqp;
5751 /* If the queue was empty, set the last pointer. */
5752 if (ascq->q_last[tid] == NULL) {
5753 ascq->q_last[tid] = reqp;
5754 }
5755 } else { /* ASC_BACK */
5756 if (ascq->q_last[tid] != NULL) {
5757 ascq->q_last[tid]->host_scribble =
5758 (unsigned char *)reqp;
5759 }
5760 ascq->q_last[tid] = reqp;
5761 reqp->host_scribble = NULL;
5762 /* If the queue was empty, set the first pointer. */
5763 if (ascq->q_first[tid] == NULL) {
5764 ascq->q_first[tid] = reqp;
5765 }
5766 }
5767 /* The queue has at least one entry, set its bit. */
5768 ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005770 /* Maintain request queue statistics. */
5771 ascq->q_tot_cnt[tid]++;
5772 ascq->q_cur_cnt[tid]++;
5773 if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
5774 ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
5775 ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
5776 tid, ascq->q_max_cnt[tid]);
5777 }
5778 REQPTIME(reqp) = REQTIMESTAMP();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005780 ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
5781 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782}
5783
5784/*
5785 * Return first queued 'REQP' on the specified queue for
5786 * the specified target device. Clear the 'tidmask' bit for
5787 * the device if no more commands are left queued for it.
5788 *
5789 * 'REQPNEXT(reqp)' returns reqp's next pointer.
5790 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005791static REQP asc_dequeue(asc_queue_t *ascq, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005793 REQP reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005795 ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5796 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
5797 if ((reqp = ascq->q_first[tid]) != NULL) {
5798 ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
5799 ascq->q_first[tid] = REQPNEXT(reqp);
5800 /* If the queue is empty, clear its bit and the last pointer. */
5801 if (ascq->q_first[tid] == NULL) {
5802 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5803 ASC_ASSERT(ascq->q_last[tid] == reqp);
5804 ascq->q_last[tid] = NULL;
5805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005806#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005807 /* Maintain request queue statistics. */
5808 ascq->q_cur_cnt[tid]--;
5809 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
5810 REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005812 }
5813 ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
5814 return reqp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815}
5816
5817/*
5818 * Return a pointer to a singly linked list of all the requests queued
5819 * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
5820 *
5821 * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
5822 * the last request returned in the singly linked list.
5823 *
5824 * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
5825 * then all queued requests are concatenated into one list and
5826 * returned.
5827 *
5828 * Note: If 'lastpp' is used to append a new list to the end of
5829 * an old list, only change the old list last pointer if '*lastpp'
5830 * (or the function return value) is not NULL, i.e. use a temporary
5831 * variable for 'lastpp' and check its value after the function return
5832 * before assigning it to the list last pointer.
5833 *
5834 * Unfortunately collecting queuing time statistics adds overhead to
5835 * the function that isn't inherent to the function's algorithm.
5836 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005837static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005838{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005839 REQP firstp, lastp;
5840 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005842 ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
5843 ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005845 /*
5846 * If 'tid' is not ASC_TID_ALL, return requests only for
5847 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
5848 * requests for all tids.
5849 */
5850 if (tid != ASC_TID_ALL) {
5851 /* Return all requests for the specified 'tid'. */
5852 if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
5853 /* List is empty; Set first and last return pointers to NULL. */
5854 firstp = lastp = NULL;
5855 } else {
5856 firstp = ascq->q_first[tid];
5857 lastp = ascq->q_last[tid];
5858 ascq->q_first[tid] = ascq->q_last[tid] = NULL;
5859 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005861 {
5862 REQP reqp;
5863 ascq->q_cur_cnt[tid] = 0;
5864 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5865 REQTIMESTAT("asc_dequeue_list", ascq,
5866 reqp, tid);
5867 }
5868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005870 }
5871 } else {
5872 /* Return all requests for all tids. */
5873 firstp = lastp = NULL;
5874 for (i = 0; i <= ADV_MAX_TID; i++) {
5875 if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
5876 if (firstp == NULL) {
5877 firstp = ascq->q_first[i];
5878 lastp = ascq->q_last[i];
5879 } else {
5880 ASC_ASSERT(lastp != NULL);
5881 lastp->host_scribble =
5882 (unsigned char *)ascq->q_first[i];
5883 lastp = ascq->q_last[i];
5884 }
5885 ascq->q_first[i] = ascq->q_last[i] = NULL;
5886 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005888 ascq->q_cur_cnt[i] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005890 }
5891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005893 {
5894 REQP reqp;
5895 for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
5896 REQTIMESTAT("asc_dequeue_list", ascq, reqp,
5897 reqp->device->id);
5898 }
5899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005901 }
5902 if (lastpp) {
5903 *lastpp = lastp;
5904 }
5905 ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
5906 return firstp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907}
5908
5909/*
5910 * Remove the specified 'REQP' from the specified queue for
5911 * the specified target device. Clear the 'tidmask' bit for the
5912 * device if no more commands are left queued for it.
5913 *
5914 * 'REQPNEXT(reqp)' returns reqp's the next pointer.
5915 *
5916 * Return ASC_TRUE if the command was found and removed,
5917 * otherwise return ASC_FALSE.
5918 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005919static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005921 REQP currp, prevp;
5922 int tid;
5923 int ret = ASC_FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005925 ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
5926 (ulong)ascq, (ulong)reqp);
5927 ASC_ASSERT(reqp != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005929 tid = REQPTID(reqp);
5930 ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005932 /*
5933 * Handle the common case of 'reqp' being the first
5934 * entry on the queue.
5935 */
5936 if (reqp == ascq->q_first[tid]) {
5937 ret = ASC_TRUE;
5938 ascq->q_first[tid] = REQPNEXT(reqp);
5939 /* If the queue is now empty, clear its bit and the last pointer. */
5940 if (ascq->q_first[tid] == NULL) {
5941 ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
5942 ASC_ASSERT(ascq->q_last[tid] == reqp);
5943 ascq->q_last[tid] = NULL;
5944 }
5945 } else if (ascq->q_first[tid] != NULL) {
5946 ASC_ASSERT(ascq->q_last[tid] != NULL);
5947 /*
5948 * Because the case of 'reqp' being the first entry has been
5949 * handled above and it is known the queue is not empty, if
5950 * 'reqp' is found on the queue it is guaranteed the queue will
5951 * not become empty and that 'q_first[tid]' will not be changed.
5952 *
5953 * Set 'prevp' to the first entry, 'currp' to the second entry,
5954 * and search for 'reqp'.
5955 */
5956 for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
5957 currp; prevp = currp, currp = REQPNEXT(currp)) {
5958 if (currp == reqp) {
5959 ret = ASC_TRUE;
5960 prevp->host_scribble =
5961 (unsigned char *)REQPNEXT(currp);
5962 reqp->host_scribble = NULL;
5963 if (ascq->q_last[tid] == reqp) {
5964 ascq->q_last[tid] = prevp;
5965 }
5966 break;
5967 }
5968 }
5969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970#ifdef ADVANSYS_STATS
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005971 /* Maintain request queue statistics. */
5972 if (ret == ASC_TRUE) {
5973 ascq->q_cur_cnt[tid]--;
5974 REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
5975 }
5976 ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977#endif /* ADVANSYS_STATS */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005978 ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
5979 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980}
5981
5982/*
5983 * Execute as many queued requests as possible for the specified queue.
5984 *
5985 * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
5986 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005987static void asc_execute_queue(asc_queue_t *ascq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005989 ADV_SCSI_BIT_ID_TYPE scan_tidmask;
5990 REQP reqp;
5991 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992
Matthew Wilcox27c868c2007-07-26 10:56:23 -04005993 ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
5994 /*
5995 * Execute queued commands for devices attached to
5996 * the current board in round-robin fashion.
5997 */
5998 scan_tidmask = ascq->q_tidmask;
5999 do {
6000 for (i = 0; i <= ADV_MAX_TID; i++) {
6001 if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
6002 if ((reqp = asc_dequeue(ascq, i)) == NULL) {
6003 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6004 } else
6005 if (asc_execute_scsi_cmnd
6006 ((struct scsi_cmnd *)reqp)
6007 == ASC_BUSY) {
6008 scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
6009 /*
6010 * The request returned ASC_BUSY. Enqueue at the front of
6011 * target's waiting list to maintain correct ordering.
6012 */
6013 asc_enqueue(ascq, reqp, ASC_FRONT);
6014 }
6015 }
6016 }
6017 } while (scan_tidmask);
6018 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019}
6020
6021#ifdef CONFIG_PROC_FS
6022/*
6023 * asc_prt_board_devices()
6024 *
6025 * Print driver information for devices attached to the board.
6026 *
6027 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6028 * cf. asc_prt_line().
6029 *
6030 * Return the number of characters copied into 'cp'. No more than
6031 * 'cplen' characters will be copied to 'cp'.
6032 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006033static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006034{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006035 asc_board_t *boardp;
6036 int leftlen;
6037 int totlen;
6038 int len;
6039 int chip_scsi_id;
6040 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006042 boardp = ASC_BOARDP(shost);
6043 leftlen = cplen;
6044 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006046 len = asc_prt_line(cp, leftlen,
6047 "\nDevice Information for AdvanSys SCSI Host %d:\n",
6048 shost->host_no);
6049 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006051 if (ASC_NARROW_BOARD(boardp)) {
6052 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6053 } else {
6054 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006057 len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
6058 ASC_PRT_NEXT();
6059 for (i = 0; i <= ADV_MAX_TID; i++) {
6060 if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
6061 len = asc_prt_line(cp, leftlen, " %X,", i);
6062 ASC_PRT_NEXT();
6063 }
6064 }
6065 len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
6066 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006068 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069}
6070
6071/*
6072 * Display Wide Board BIOS Information.
6073 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006074static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006075{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006076 asc_board_t *boardp;
6077 int leftlen;
6078 int totlen;
6079 int len;
6080 ushort major, minor, letter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006082 boardp = ASC_BOARDP(shost);
6083 leftlen = cplen;
6084 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006086 len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
6087 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006089 /*
6090 * If the BIOS saved a valid signature, then fill in
6091 * the BIOS code segment base address.
6092 */
6093 if (boardp->bios_signature != 0x55AA) {
6094 len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
6095 ASC_PRT_NEXT();
6096 len = asc_prt_line(cp, leftlen,
6097 "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
6098 ASC_PRT_NEXT();
6099 len = asc_prt_line(cp, leftlen,
6100 "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
6101 ASC_PRT_NEXT();
6102 } else {
6103 major = (boardp->bios_version >> 12) & 0xF;
6104 minor = (boardp->bios_version >> 8) & 0xF;
6105 letter = (boardp->bios_version & 0xFF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006107 len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
6108 major, minor,
6109 letter >= 26 ? '?' : letter + 'A');
6110 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006112 /*
6113 * Current available ROM BIOS release is 3.1I for UW
6114 * and 3.2I for U2W. This code doesn't differentiate
6115 * UW and U2W boards.
6116 */
6117 if (major < 3 || (major <= 3 && minor < 1) ||
6118 (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
6119 len = asc_prt_line(cp, leftlen,
6120 "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
6121 ASC_PRT_NEXT();
6122 len = asc_prt_line(cp, leftlen,
6123 "ftp://ftp.connectcom.net/pub\n");
6124 ASC_PRT_NEXT();
6125 }
6126 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006128 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129}
6130
6131/*
6132 * Add serial number to information bar if signature AAh
6133 * is found in at bit 15-9 (7 bits) of word 1.
6134 *
6135 * Serial Number consists fo 12 alpha-numeric digits.
6136 *
6137 * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
6138 * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
6139 * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits)
6140 * 5 - Product revision (A-J) Word0: " "
6141 *
6142 * Signature Word1: 15-9 (7 bits)
6143 * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
6144 * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits)
6145 *
6146 * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
6147 *
6148 * Note 1: Only production cards will have a serial number.
6149 *
6150 * Note 2: Signature is most significant 7 bits (0xFE).
6151 *
6152 * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
6153 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006154static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006156 ushort w, num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006158 if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
6159 return ASC_FALSE;
6160 } else {
6161 /*
6162 * First word - 6 digits.
6163 */
6164 w = serialnum[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006166 /* Product type - 1st digit. */
6167 if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
6168 /* Product type is P=Prototype */
6169 *cp += 0x8;
6170 }
6171 cp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006172
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006173 /* Manufacturing location - 2nd digit. */
6174 *cp++ = 'A' + ((w & 0x1C00) >> 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006175
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006176 /* Product ID - 3rd, 4th digits. */
6177 num = w & 0x3FF;
6178 *cp++ = '0' + (num / 100);
6179 num %= 100;
6180 *cp++ = '0' + (num / 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006181
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006182 /* Product revision - 5th digit. */
6183 *cp++ = 'A' + (num % 10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006184
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006185 /*
6186 * Second word
6187 */
6188 w = serialnum[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006190 /*
6191 * Year - 6th digit.
6192 *
6193 * If bit 15 of third word is set, then the
6194 * last digit of the year is greater than 7.
6195 */
6196 if (serialnum[2] & 0x8000) {
6197 *cp++ = '8' + ((w & 0x1C0) >> 6);
6198 } else {
6199 *cp++ = '0' + ((w & 0x1C0) >> 6);
6200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006201
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006202 /* Week of year - 7th, 8th digits. */
6203 num = w & 0x003F;
6204 *cp++ = '0' + num / 10;
6205 num %= 10;
6206 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006208 /*
6209 * Third word
6210 */
6211 w = serialnum[2] & 0x7FFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006213 /* Serial number - 9th digit. */
6214 *cp++ = 'A' + (w / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006215
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006216 /* 10th, 11th, 12th digits. */
6217 num = w % 1000;
6218 *cp++ = '0' + num / 100;
6219 num %= 100;
6220 *cp++ = '0' + num / 10;
6221 num %= 10;
6222 *cp++ = '0' + num;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006224 *cp = '\0'; /* Null Terminate the string. */
6225 return ASC_TRUE;
6226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227}
6228
6229/*
6230 * asc_prt_asc_board_eeprom()
6231 *
6232 * Print board EEPROM configuration.
6233 *
6234 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6235 * cf. asc_prt_line().
6236 *
6237 * Return the number of characters copied into 'cp'. No more than
6238 * 'cplen' characters will be copied to 'cp'.
6239 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006240static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006242 asc_board_t *boardp;
6243 ASC_DVC_VAR *asc_dvc_varp;
6244 int leftlen;
6245 int totlen;
6246 int len;
6247 ASCEEP_CONFIG *ep;
6248 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006250 int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006252 uchar serialstr[13];
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006254 boardp = ASC_BOARDP(shost);
6255 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
6256 ep = &boardp->eep_config.asc_eep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006258 leftlen = cplen;
6259 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006261 len = asc_prt_line(cp, leftlen,
6262 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6263 shost->host_no);
6264 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006266 if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
6267 == ASC_TRUE) {
6268 len =
6269 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6270 serialstr);
6271 ASC_PRT_NEXT();
6272 } else {
6273 if (ep->adapter_info[5] == 0xBB) {
6274 len = asc_prt_line(cp, leftlen,
6275 " Default Settings Used for EEPROM-less Adapter.\n");
6276 ASC_PRT_NEXT();
6277 } else {
6278 len = asc_prt_line(cp, leftlen,
6279 " Serial Number Signature Not Present.\n");
6280 ASC_PRT_NEXT();
6281 }
6282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006284 len = asc_prt_line(cp, leftlen,
6285 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6286 ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
6287 ep->max_tag_qng);
6288 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006290 len = asc_prt_line(cp, leftlen,
6291 " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
6292 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006294 len = asc_prt_line(cp, leftlen, " Target ID: ");
6295 ASC_PRT_NEXT();
6296 for (i = 0; i <= ASC_MAX_TID; i++) {
6297 len = asc_prt_line(cp, leftlen, " %d", i);
6298 ASC_PRT_NEXT();
6299 }
6300 len = asc_prt_line(cp, leftlen, "\n");
6301 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006303 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6304 ASC_PRT_NEXT();
6305 for (i = 0; i <= ASC_MAX_TID; i++) {
6306 len = asc_prt_line(cp, leftlen, " %c",
6307 (ep->
6308 disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6309 'N');
6310 ASC_PRT_NEXT();
6311 }
6312 len = asc_prt_line(cp, leftlen, "\n");
6313 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006315 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6316 ASC_PRT_NEXT();
6317 for (i = 0; i <= ASC_MAX_TID; i++) {
6318 len = asc_prt_line(cp, leftlen, " %c",
6319 (ep->
6320 use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6321 'N');
6322 ASC_PRT_NEXT();
6323 }
6324 len = asc_prt_line(cp, leftlen, "\n");
6325 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006327 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6328 ASC_PRT_NEXT();
6329 for (i = 0; i <= ASC_MAX_TID; i++) {
6330 len = asc_prt_line(cp, leftlen, " %c",
6331 (ep->
6332 start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6333 'N');
6334 ASC_PRT_NEXT();
6335 }
6336 len = asc_prt_line(cp, leftlen, "\n");
6337 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006339 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6340 ASC_PRT_NEXT();
6341 for (i = 0; i <= ASC_MAX_TID; i++) {
6342 len = asc_prt_line(cp, leftlen, " %c",
6343 (ep->
6344 init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6345 'N');
6346 ASC_PRT_NEXT();
6347 }
6348 len = asc_prt_line(cp, leftlen, "\n");
6349 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350
6351#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006352 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
6353 len = asc_prt_line(cp, leftlen,
6354 " Host ISA DMA speed: %d MB/S\n",
6355 isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
6356 ASC_PRT_NEXT();
6357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358#endif /* CONFIG_ISA */
6359
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006360 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006361}
6362
6363/*
6364 * asc_prt_adv_board_eeprom()
6365 *
6366 * Print board EEPROM configuration.
6367 *
6368 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6369 * cf. asc_prt_line().
6370 *
6371 * Return the number of characters copied into 'cp'. No more than
6372 * 'cplen' characters will be copied to 'cp'.
6373 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006374static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006376 asc_board_t *boardp;
6377 ADV_DVC_VAR *adv_dvc_varp;
6378 int leftlen;
6379 int totlen;
6380 int len;
6381 int i;
6382 char *termstr;
6383 uchar serialstr[13];
6384 ADVEEP_3550_CONFIG *ep_3550 = NULL;
6385 ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
6386 ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
6387 ushort word;
6388 ushort *wordp;
6389 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006390
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006391 boardp = ASC_BOARDP(shost);
6392 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
6393 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6394 ep_3550 = &boardp->eep_config.adv_3550_eep;
6395 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6396 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
6397 } else {
6398 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
6399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006400
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006401 leftlen = cplen;
6402 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006404 len = asc_prt_line(cp, leftlen,
6405 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
6406 shost->host_no);
6407 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006409 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6410 wordp = &ep_3550->serial_number_word1;
6411 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6412 wordp = &ep_38C0800->serial_number_word1;
6413 } else {
6414 wordp = &ep_38C1600->serial_number_word1;
6415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006416
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006417 if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
6418 len =
6419 asc_prt_line(cp, leftlen, " Serial Number: %s\n",
6420 serialstr);
6421 ASC_PRT_NEXT();
6422 } else {
6423 len = asc_prt_line(cp, leftlen,
6424 " Serial Number Signature Not Present.\n");
6425 ASC_PRT_NEXT();
6426 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006427
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006428 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6429 len = asc_prt_line(cp, leftlen,
6430 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6431 ep_3550->adapter_scsi_id,
6432 ep_3550->max_host_qng, ep_3550->max_dvc_qng);
6433 ASC_PRT_NEXT();
6434 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6435 len = asc_prt_line(cp, leftlen,
6436 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6437 ep_38C0800->adapter_scsi_id,
6438 ep_38C0800->max_host_qng,
6439 ep_38C0800->max_dvc_qng);
6440 ASC_PRT_NEXT();
6441 } else {
6442 len = asc_prt_line(cp, leftlen,
6443 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
6444 ep_38C1600->adapter_scsi_id,
6445 ep_38C1600->max_host_qng,
6446 ep_38C1600->max_dvc_qng);
6447 ASC_PRT_NEXT();
6448 }
6449 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6450 word = ep_3550->termination;
6451 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6452 word = ep_38C0800->termination_lvd;
6453 } else {
6454 word = ep_38C1600->termination_lvd;
6455 }
6456 switch (word) {
6457 case 1:
6458 termstr = "Low Off/High Off";
6459 break;
6460 case 2:
6461 termstr = "Low Off/High On";
6462 break;
6463 case 3:
6464 termstr = "Low On/High On";
6465 break;
6466 default:
6467 case 0:
6468 termstr = "Automatic";
6469 break;
6470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006472 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6473 len = asc_prt_line(cp, leftlen,
6474 " termination: %u (%s), bios_ctrl: 0x%x\n",
6475 ep_3550->termination, termstr,
6476 ep_3550->bios_ctrl);
6477 ASC_PRT_NEXT();
6478 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6479 len = asc_prt_line(cp, leftlen,
6480 " termination: %u (%s), bios_ctrl: 0x%x\n",
6481 ep_38C0800->termination_lvd, termstr,
6482 ep_38C0800->bios_ctrl);
6483 ASC_PRT_NEXT();
6484 } else {
6485 len = asc_prt_line(cp, leftlen,
6486 " termination: %u (%s), bios_ctrl: 0x%x\n",
6487 ep_38C1600->termination_lvd, termstr,
6488 ep_38C1600->bios_ctrl);
6489 ASC_PRT_NEXT();
6490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006492 len = asc_prt_line(cp, leftlen, " Target ID: ");
6493 ASC_PRT_NEXT();
6494 for (i = 0; i <= ADV_MAX_TID; i++) {
6495 len = asc_prt_line(cp, leftlen, " %X", i);
6496 ASC_PRT_NEXT();
6497 }
6498 len = asc_prt_line(cp, leftlen, "\n");
6499 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006500
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006501 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6502 word = ep_3550->disc_enable;
6503 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6504 word = ep_38C0800->disc_enable;
6505 } else {
6506 word = ep_38C1600->disc_enable;
6507 }
6508 len = asc_prt_line(cp, leftlen, " Disconnects: ");
6509 ASC_PRT_NEXT();
6510 for (i = 0; i <= ADV_MAX_TID; i++) {
6511 len = asc_prt_line(cp, leftlen, " %c",
6512 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6513 ASC_PRT_NEXT();
6514 }
6515 len = asc_prt_line(cp, leftlen, "\n");
6516 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006517
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006518 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6519 word = ep_3550->tagqng_able;
6520 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6521 word = ep_38C0800->tagqng_able;
6522 } else {
6523 word = ep_38C1600->tagqng_able;
6524 }
6525 len = asc_prt_line(cp, leftlen, " Command Queuing: ");
6526 ASC_PRT_NEXT();
6527 for (i = 0; i <= ADV_MAX_TID; i++) {
6528 len = asc_prt_line(cp, leftlen, " %c",
6529 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6530 ASC_PRT_NEXT();
6531 }
6532 len = asc_prt_line(cp, leftlen, "\n");
6533 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006534
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006535 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6536 word = ep_3550->start_motor;
6537 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6538 word = ep_38C0800->start_motor;
6539 } else {
6540 word = ep_38C1600->start_motor;
6541 }
6542 len = asc_prt_line(cp, leftlen, " Start Motor: ");
6543 ASC_PRT_NEXT();
6544 for (i = 0; i <= ADV_MAX_TID; i++) {
6545 len = asc_prt_line(cp, leftlen, " %c",
6546 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6547 ASC_PRT_NEXT();
6548 }
6549 len = asc_prt_line(cp, leftlen, "\n");
6550 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006551
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006552 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6553 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6554 ASC_PRT_NEXT();
6555 for (i = 0; i <= ADV_MAX_TID; i++) {
6556 len = asc_prt_line(cp, leftlen, " %c",
6557 (ep_3550->
6558 sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
6559 'Y' : 'N');
6560 ASC_PRT_NEXT();
6561 }
6562 len = asc_prt_line(cp, leftlen, "\n");
6563 ASC_PRT_NEXT();
6564 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006565
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006566 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6567 len = asc_prt_line(cp, leftlen, " Ultra Transfer: ");
6568 ASC_PRT_NEXT();
6569 for (i = 0; i <= ADV_MAX_TID; i++) {
6570 len = asc_prt_line(cp, leftlen, " %c",
6571 (ep_3550->
6572 ultra_able & ADV_TID_TO_TIDMASK(i))
6573 ? 'Y' : 'N');
6574 ASC_PRT_NEXT();
6575 }
6576 len = asc_prt_line(cp, leftlen, "\n");
6577 ASC_PRT_NEXT();
6578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006579
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006580 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
6581 word = ep_3550->wdtr_able;
6582 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
6583 word = ep_38C0800->wdtr_able;
6584 } else {
6585 word = ep_38C1600->wdtr_able;
6586 }
6587 len = asc_prt_line(cp, leftlen, " Wide Transfer: ");
6588 ASC_PRT_NEXT();
6589 for (i = 0; i <= ADV_MAX_TID; i++) {
6590 len = asc_prt_line(cp, leftlen, " %c",
6591 (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
6592 ASC_PRT_NEXT();
6593 }
6594 len = asc_prt_line(cp, leftlen, "\n");
6595 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006596
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006597 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
6598 adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
6599 len = asc_prt_line(cp, leftlen,
6600 " Synchronous Transfer Speed (Mhz):\n ");
6601 ASC_PRT_NEXT();
6602 for (i = 0; i <= ADV_MAX_TID; i++) {
6603 char *speed_str;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006604
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006605 if (i == 0) {
6606 sdtr_speed = adv_dvc_varp->sdtr_speed1;
6607 } else if (i == 4) {
6608 sdtr_speed = adv_dvc_varp->sdtr_speed2;
6609 } else if (i == 8) {
6610 sdtr_speed = adv_dvc_varp->sdtr_speed3;
6611 } else if (i == 12) {
6612 sdtr_speed = adv_dvc_varp->sdtr_speed4;
6613 }
6614 switch (sdtr_speed & ADV_MAX_TID) {
6615 case 0:
6616 speed_str = "Off";
6617 break;
6618 case 1:
6619 speed_str = " 5";
6620 break;
6621 case 2:
6622 speed_str = " 10";
6623 break;
6624 case 3:
6625 speed_str = " 20";
6626 break;
6627 case 4:
6628 speed_str = " 40";
6629 break;
6630 case 5:
6631 speed_str = " 80";
6632 break;
6633 default:
6634 speed_str = "Unk";
6635 break;
6636 }
6637 len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
6638 ASC_PRT_NEXT();
6639 if (i == 7) {
6640 len = asc_prt_line(cp, leftlen, "\n ");
6641 ASC_PRT_NEXT();
6642 }
6643 sdtr_speed >>= 4;
6644 }
6645 len = asc_prt_line(cp, leftlen, "\n");
6646 ASC_PRT_NEXT();
6647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006648
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006649 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006650}
6651
6652/*
6653 * asc_prt_driver_conf()
6654 *
6655 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6656 * cf. asc_prt_line().
6657 *
6658 * Return the number of characters copied into 'cp'. No more than
6659 * 'cplen' characters will be copied to 'cp'.
6660 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006661static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006662{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006663 asc_board_t *boardp;
6664 int leftlen;
6665 int totlen;
6666 int len;
6667 int chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006668
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006669 boardp = ASC_BOARDP(shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006670
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006671 leftlen = cplen;
6672 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006673
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006674 len = asc_prt_line(cp, leftlen,
6675 "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
6676 shost->host_no);
6677 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006678
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006679 len = asc_prt_line(cp, leftlen,
6680 " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
6681 shost->host_busy, shost->last_reset, shost->max_id,
6682 shost->max_lun, shost->max_channel);
6683 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006684
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006685 len = asc_prt_line(cp, leftlen,
6686 " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
6687 shost->unique_id, shost->can_queue, shost->this_id,
6688 shost->sg_tablesize, shost->cmd_per_lun);
6689 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006690
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006691 len = asc_prt_line(cp, leftlen,
6692 " unchecked_isa_dma %d, use_clustering %d\n",
6693 shost->unchecked_isa_dma, shost->use_clustering);
6694 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006696 len = asc_prt_line(cp, leftlen,
6697 " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
6698 boardp->flags, boardp->last_reset, jiffies,
6699 boardp->asc_n_io_port);
6700 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006701
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006702 /* 'shost->n_io_port' may be truncated because it is only one byte. */
6703 len = asc_prt_line(cp, leftlen,
6704 " io_port 0x%x, n_io_port 0x%x\n",
6705 shost->io_port, shost->n_io_port);
6706 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006707
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006708 if (ASC_NARROW_BOARD(boardp)) {
6709 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
6710 } else {
6711 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
6712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006714 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006715}
6716
6717/*
6718 * asc_prt_asc_board_info()
6719 *
6720 * Print dynamic board configuration information.
6721 *
6722 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6723 * cf. asc_prt_line().
6724 *
6725 * Return the number of characters copied into 'cp'. No more than
6726 * 'cplen' characters will be copied to 'cp'.
6727 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006728static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006729{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006730 asc_board_t *boardp;
6731 int chip_scsi_id;
6732 int leftlen;
6733 int totlen;
6734 int len;
6735 ASC_DVC_VAR *v;
6736 ASC_DVC_CFG *c;
6737 int i;
6738 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006739
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006740 boardp = ASC_BOARDP(shost);
6741 v = &boardp->dvc_var.asc_dvc_var;
6742 c = &boardp->dvc_cfg.asc_dvc_cfg;
6743 chip_scsi_id = c->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006744
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006745 leftlen = cplen;
6746 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006748 len = asc_prt_line(cp, leftlen,
6749 "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6750 shost->host_no);
6751 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006752
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006753 len = asc_prt_line(cp, leftlen,
6754 " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
6755 c->chip_version, c->lib_version, c->lib_serial_no,
6756 c->mcode_date);
6757 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006759 len = asc_prt_line(cp, leftlen,
6760 " mcode_version 0x%x, err_code %u\n",
6761 c->mcode_version, v->err_code);
6762 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006764 /* Current number of commands waiting for the host. */
6765 len = asc_prt_line(cp, leftlen,
6766 " Total Command Pending: %d\n", v->cur_total_qng);
6767 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006769 len = asc_prt_line(cp, leftlen, " Command Queuing:");
6770 ASC_PRT_NEXT();
6771 for (i = 0; i <= ASC_MAX_TID; i++) {
6772 if ((chip_scsi_id == i) ||
6773 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6774 continue;
6775 }
6776 len = asc_prt_line(cp, leftlen, " %X:%c",
6777 i,
6778 (v->
6779 use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
6780 'Y' : 'N');
6781 ASC_PRT_NEXT();
6782 }
6783 len = asc_prt_line(cp, leftlen, "\n");
6784 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006785
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006786 /* Current number of commands waiting for a device. */
6787 len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
6788 ASC_PRT_NEXT();
6789 for (i = 0; i <= ASC_MAX_TID; i++) {
6790 if ((chip_scsi_id == i) ||
6791 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6792 continue;
6793 }
6794 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
6795 ASC_PRT_NEXT();
6796 }
6797 len = asc_prt_line(cp, leftlen, "\n");
6798 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006799
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006800 /* Current limit on number of commands that can be sent to a device. */
6801 len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
6802 ASC_PRT_NEXT();
6803 for (i = 0; i <= ASC_MAX_TID; i++) {
6804 if ((chip_scsi_id == i) ||
6805 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6806 continue;
6807 }
6808 len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
6809 ASC_PRT_NEXT();
6810 }
6811 len = asc_prt_line(cp, leftlen, "\n");
6812 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006813
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006814 /* Indicate whether the device has returned queue full status. */
6815 len = asc_prt_line(cp, leftlen, " Command Queue Full:");
6816 ASC_PRT_NEXT();
6817 for (i = 0; i <= ASC_MAX_TID; i++) {
6818 if ((chip_scsi_id == i) ||
6819 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6820 continue;
6821 }
6822 if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
6823 len = asc_prt_line(cp, leftlen, " %X:Y-%d",
6824 i, boardp->queue_full_cnt[i]);
6825 } else {
6826 len = asc_prt_line(cp, leftlen, " %X:N", i);
6827 }
6828 ASC_PRT_NEXT();
6829 }
6830 len = asc_prt_line(cp, leftlen, "\n");
6831 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006832
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006833 len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
6834 ASC_PRT_NEXT();
6835 for (i = 0; i <= ASC_MAX_TID; i++) {
6836 if ((chip_scsi_id == i) ||
6837 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6838 continue;
6839 }
6840 len = asc_prt_line(cp, leftlen, " %X:%c",
6841 i,
6842 (v->
6843 sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6844 'N');
6845 ASC_PRT_NEXT();
6846 }
6847 len = asc_prt_line(cp, leftlen, "\n");
6848 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006849
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006850 for (i = 0; i <= ASC_MAX_TID; i++) {
6851 uchar syn_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006852
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006853 if ((chip_scsi_id == i) ||
6854 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
6855 ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
6856 continue;
6857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006858
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006859 len = asc_prt_line(cp, leftlen, " %X:", i);
6860 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006861
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006862 if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
6863 len = asc_prt_line(cp, leftlen, " Asynchronous");
6864 ASC_PRT_NEXT();
6865 } else {
6866 syn_period_ix =
6867 (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
6868 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006869
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006870 len = asc_prt_line(cp, leftlen,
6871 " Transfer Period Factor: %d (%d.%d Mhz),",
6872 v->sdtr_period_tbl[syn_period_ix],
6873 250 /
6874 v->sdtr_period_tbl[syn_period_ix],
6875 ASC_TENTHS(250,
6876 v->
6877 sdtr_period_tbl
6878 [syn_period_ix]));
6879 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006880
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006881 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
6882 boardp->
6883 sdtr_data[i] & ASC_SYN_MAX_OFFSET);
6884 ASC_PRT_NEXT();
6885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006887 if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
6888 len = asc_prt_line(cp, leftlen, "*\n");
6889 renegotiate = 1;
6890 } else {
6891 len = asc_prt_line(cp, leftlen, "\n");
6892 }
6893 ASC_PRT_NEXT();
6894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006895
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006896 if (renegotiate) {
6897 len = asc_prt_line(cp, leftlen,
6898 " * = Re-negotiation pending before next command.\n");
6899 ASC_PRT_NEXT();
6900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006901
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006902 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006903}
6904
6905/*
6906 * asc_prt_adv_board_info()
6907 *
6908 * Print dynamic board configuration information.
6909 *
6910 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
6911 * cf. asc_prt_line().
6912 *
6913 * Return the number of characters copied into 'cp'. No more than
6914 * 'cplen' characters will be copied to 'cp'.
6915 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006916static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006917{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006918 asc_board_t *boardp;
6919 int leftlen;
6920 int totlen;
6921 int len;
6922 int i;
6923 ADV_DVC_VAR *v;
6924 ADV_DVC_CFG *c;
6925 AdvPortAddr iop_base;
6926 ushort chip_scsi_id;
6927 ushort lramword;
6928 uchar lrambyte;
6929 ushort tagqng_able;
6930 ushort sdtr_able, wdtr_able;
6931 ushort wdtr_done, sdtr_done;
6932 ushort period = 0;
6933 int renegotiate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006934
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006935 boardp = ASC_BOARDP(shost);
6936 v = &boardp->dvc_var.adv_dvc_var;
6937 c = &boardp->dvc_cfg.adv_dvc_cfg;
6938 iop_base = v->iop_base;
6939 chip_scsi_id = v->chip_scsi_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006940
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006941 leftlen = cplen;
6942 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006943
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006944 len = asc_prt_line(cp, leftlen,
6945 "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
6946 shost->host_no);
6947 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006948
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006949 len = asc_prt_line(cp, leftlen,
6950 " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
6951 v->iop_base,
6952 AdvReadWordRegister(iop_base,
6953 IOPW_SCSI_CFG1) & CABLE_DETECT,
6954 v->err_code);
6955 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006956
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006957 len = asc_prt_line(cp, leftlen,
6958 " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
6959 c->chip_version, c->lib_version, c->mcode_date,
6960 c->mcode_version);
6961 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006962
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006963 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
6964 len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
6965 ASC_PRT_NEXT();
6966 for (i = 0; i <= ADV_MAX_TID; i++) {
6967 if ((chip_scsi_id == i) ||
6968 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6969 continue;
6970 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006971
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006972 len = asc_prt_line(cp, leftlen, " %X:%c",
6973 i,
6974 (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
6975 'N');
6976 ASC_PRT_NEXT();
6977 }
6978 len = asc_prt_line(cp, leftlen, "\n");
6979 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006980
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006981 len = asc_prt_line(cp, leftlen, " Queue Limit:");
6982 ASC_PRT_NEXT();
6983 for (i = 0; i <= ADV_MAX_TID; i++) {
6984 if ((chip_scsi_id == i) ||
6985 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
6986 continue;
6987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006988
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006989 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
6990 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006991
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006992 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
6993 ASC_PRT_NEXT();
6994 }
6995 len = asc_prt_line(cp, leftlen, "\n");
6996 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07006997
Matthew Wilcox27c868c2007-07-26 10:56:23 -04006998 len = asc_prt_line(cp, leftlen, " Command Pending:");
6999 ASC_PRT_NEXT();
7000 for (i = 0; i <= ADV_MAX_TID; i++) {
7001 if ((chip_scsi_id == i) ||
7002 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7003 continue;
7004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007005
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007006 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
7007 lrambyte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007008
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007009 len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
7010 ASC_PRT_NEXT();
7011 }
7012 len = asc_prt_line(cp, leftlen, "\n");
7013 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007014
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007015 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
7016 len = asc_prt_line(cp, leftlen, " Wide Enabled:");
7017 ASC_PRT_NEXT();
7018 for (i = 0; i <= ADV_MAX_TID; i++) {
7019 if ((chip_scsi_id == i) ||
7020 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7021 continue;
7022 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007023
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007024 len = asc_prt_line(cp, leftlen, " %X:%c",
7025 i,
7026 (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7027 'N');
7028 ASC_PRT_NEXT();
7029 }
7030 len = asc_prt_line(cp, leftlen, "\n");
7031 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007032
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007033 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
7034 len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
7035 ASC_PRT_NEXT();
7036 for (i = 0; i <= ADV_MAX_TID; i++) {
7037 if ((chip_scsi_id == i) ||
7038 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7039 continue;
7040 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007041
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007042 AdvReadWordLram(iop_base,
7043 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7044 lramword);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007045
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007046 len = asc_prt_line(cp, leftlen, " %X:%d",
7047 i, (lramword & 0x8000) ? 16 : 8);
7048 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007049
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007050 if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
7051 (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7052 len = asc_prt_line(cp, leftlen, "*");
7053 ASC_PRT_NEXT();
7054 renegotiate = 1;
7055 }
7056 }
7057 len = asc_prt_line(cp, leftlen, "\n");
7058 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007059
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007060 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
7061 len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
7062 ASC_PRT_NEXT();
7063 for (i = 0; i <= ADV_MAX_TID; i++) {
7064 if ((chip_scsi_id == i) ||
7065 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
7066 continue;
7067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007068
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007069 len = asc_prt_line(cp, leftlen, " %X:%c",
7070 i,
7071 (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
7072 'N');
7073 ASC_PRT_NEXT();
7074 }
7075 len = asc_prt_line(cp, leftlen, "\n");
7076 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007077
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007078 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
7079 for (i = 0; i <= ADV_MAX_TID; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007080
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007081 AdvReadWordLram(iop_base,
7082 ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
7083 lramword);
7084 lramword &= ~0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007085
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007086 if ((chip_scsi_id == i) ||
7087 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
7088 ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
7089 continue;
7090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007091
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007092 len = asc_prt_line(cp, leftlen, " %X:", i);
7093 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007094
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007095 if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
7096 len = asc_prt_line(cp, leftlen, " Asynchronous");
7097 ASC_PRT_NEXT();
7098 } else {
7099 len =
7100 asc_prt_line(cp, leftlen,
7101 " Transfer Period Factor: ");
7102 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007103
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007104 if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
7105 len =
7106 asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
7107 ASC_PRT_NEXT();
7108 } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
7109 len =
7110 asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
7111 ASC_PRT_NEXT();
7112 } else { /* 20 Mhz or below. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007113
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007114 period = (((lramword >> 8) * 25) + 50) / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007115
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007116 if (period == 0) { /* Should never happen. */
7117 len =
7118 asc_prt_line(cp, leftlen,
7119 "%d (? Mhz), ");
7120 ASC_PRT_NEXT();
7121 } else {
7122 len = asc_prt_line(cp, leftlen,
7123 "%d (%d.%d Mhz),",
7124 period, 250 / period,
7125 ASC_TENTHS(250,
7126 period));
7127 ASC_PRT_NEXT();
7128 }
7129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007131 len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
7132 lramword & 0x1F);
7133 ASC_PRT_NEXT();
7134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007135
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007136 if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
7137 len = asc_prt_line(cp, leftlen, "*\n");
7138 renegotiate = 1;
7139 } else {
7140 len = asc_prt_line(cp, leftlen, "\n");
7141 }
7142 ASC_PRT_NEXT();
7143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007144
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007145 if (renegotiate) {
7146 len = asc_prt_line(cp, leftlen,
7147 " * = Re-negotiation pending before next command.\n");
7148 ASC_PRT_NEXT();
7149 }
7150
7151 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007152}
7153
7154/*
7155 * asc_proc_copy()
7156 *
7157 * Copy proc information to a read buffer taking into account the current
7158 * read offset in the file and the remaining space in the read buffer.
7159 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007160static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07007161asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007162 char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007163{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007164 int cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007165
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007166 ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
7167 (unsigned)offset, (unsigned)advoffset, cplen);
7168 if (offset <= advoffset) {
7169 /* Read offset below current offset, copy everything. */
7170 cnt = min(cplen, leftlen);
7171 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7172 (ulong)curbuf, (ulong)cp, cnt);
7173 memcpy(curbuf, cp, cnt);
7174 } else if (offset < advoffset + cplen) {
7175 /* Read offset within current range, partial copy. */
7176 cnt = (advoffset + cplen) - offset;
7177 cp = (cp + cplen) - cnt;
7178 cnt = min(cnt, leftlen);
7179 ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
7180 (ulong)curbuf, (ulong)cp, cnt);
7181 memcpy(curbuf, cp, cnt);
7182 }
7183 return cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007184}
7185
7186/*
7187 * asc_prt_line()
7188 *
7189 * If 'cp' is NULL print to the console, otherwise print to a buffer.
7190 *
7191 * Return 0 if printing to the console, otherwise return the number of
7192 * bytes written to the buffer.
7193 *
7194 * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
7195 * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
7196 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007197static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007198{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007199 va_list args;
7200 int ret;
7201 char s[ASC_PRTLINE_SIZE];
Linus Torvalds1da177e2005-04-16 15:20:36 -07007202
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007203 va_start(args, fmt);
7204 ret = vsprintf(s, fmt, args);
7205 ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
7206 if (buf == NULL) {
7207 (void)printk(s);
7208 ret = 0;
7209 } else {
7210 ret = min(buflen, ret);
7211 memcpy(buf, s, ret);
7212 }
7213 va_end(args);
7214 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007215}
7216#endif /* CONFIG_PROC_FS */
7217
Linus Torvalds1da177e2005-04-16 15:20:36 -07007218/*
7219 * --- Functions Required by the Asc Library
7220 */
7221
7222/*
7223 * Delay for 'n' milliseconds. Don't use the 'jiffies'
7224 * global variable which is incremented once every 5 ms
7225 * from a timer interrupt, because this function may be
7226 * called when interrupts are disabled.
7227 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007228static void DvcSleepMilliSecond(ADV_DCNT n)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007229{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007230 ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
7231 mdelay(n);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007232}
7233
7234/*
7235 * Currently and inline noop but leave as a placeholder.
7236 * Leave DvcEnterCritical() as a noop placeholder.
7237 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007238static inline ulong DvcEnterCritical(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007239{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007240 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007241}
7242
7243/*
7244 * Critical sections are all protected by the board spinlock.
7245 * Leave DvcLeaveCritical() as a noop placeholder.
7246 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007247static inline void DvcLeaveCritical(ulong flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007248{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007249 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007250}
7251
7252/*
7253 * void
7254 * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7255 *
7256 * Calling/Exit State:
7257 * none
7258 *
7259 * Description:
7260 * Output an ASC_SCSI_Q structure to the chip
7261 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007262static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007263DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
7264{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007265 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007266
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007267 ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
7268 AscSetChipLramAddr(iop_base, s_addr);
7269 for (i = 0; i < 2 * words; i += 2) {
7270 if (i == 4 || i == 20) {
7271 continue;
7272 }
7273 outpw(iop_base + IOP_RAM_DATA,
7274 ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
7275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007276}
7277
7278/*
7279 * void
7280 * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7281 *
7282 * Calling/Exit State:
7283 * none
7284 *
7285 * Description:
7286 * Input an ASC_QDONE_INFO structure from the chip
7287 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007288static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07007289DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
7290{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007291 int i;
7292 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007293
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007294 AscSetChipLramAddr(iop_base, s_addr);
7295 for (i = 0; i < 2 * words; i += 2) {
7296 if (i == 10) {
7297 continue;
7298 }
7299 word = inpw(iop_base + IOP_RAM_DATA);
7300 inbuf[i] = word & 0xff;
7301 inbuf[i + 1] = (word >> 8) & 0xff;
7302 }
7303 ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007304}
7305
7306/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007307 * Return the BIOS address of the adapter at the specified
7308 * I/O port and with the specified bus type.
7309 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007310static ushort __devinit AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007311{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007312 ushort cfg_lsw;
7313 ushort bios_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007314
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007315 /*
7316 * The PCI BIOS is re-located by the motherboard BIOS. Because
7317 * of this the driver can not determine where a PCI BIOS is
7318 * loaded and executes.
7319 */
7320 if (bus_type & ASC_IS_PCI) {
7321 return (0);
7322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007323#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007324 if ((bus_type & ASC_IS_EISA) != 0) {
7325 cfg_lsw = AscGetEisaChipCfg(iop_base);
7326 cfg_lsw &= 0x000F;
7327 bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
7328 (cfg_lsw * ASC_BIOS_BANK_SIZE));
7329 return (bios_addr);
7330 } /* if */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007331#endif /* CONFIG_ISA */
7332
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007333 cfg_lsw = AscGetChipCfgLsw(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007334
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007335 /*
7336 * ISA PnP uses the top bit as the 32K BIOS flag
7337 */
7338 if (bus_type == ASC_IS_ISAPNP) {
7339 cfg_lsw &= 0x7FFF;
7340 }
7341 /* if */
7342 bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
7343 ASC_BIOS_MIN_ADDR);
7344 return (bios_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007345}
7346
Linus Torvalds1da177e2005-04-16 15:20:36 -07007347/*
7348 * --- Functions Required by the Adv Library
7349 */
7350
7351/*
7352 * DvcGetPhyAddr()
7353 *
7354 * Return the physical address of 'vaddr' and set '*lenp' to the
7355 * number of physically contiguous bytes that follow 'vaddr'.
7356 * 'flag' indicates the type of structure whose physical address
7357 * is being translated.
7358 *
7359 * Note: Because Linux currently doesn't page the kernel and all
7360 * kernel buffers are physically contiguous, leave '*lenp' unchanged.
7361 */
7362ADV_PADDR
7363DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007364 uchar *vaddr, ADV_SDCNT *lenp, int flag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007365{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007366 ADV_PADDR paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007367
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007368 paddr = virt_to_bus(vaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007369
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007370 ASC_DBG4(4,
7371 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
7372 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
7373 (ulong)paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007374
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007375 return paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007376}
7377
7378/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07007379 * --- Tracing and Debugging Functions
7380 */
7381
7382#ifdef ADVANSYS_STATS
7383#ifdef CONFIG_PROC_FS
7384/*
7385 * asc_prt_board_stats()
7386 *
7387 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7388 * cf. asc_prt_line().
7389 *
7390 * Return the number of characters copied into 'cp'. No more than
7391 * 'cplen' characters will be copied to 'cp'.
7392 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007393static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007394{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007395 int leftlen;
7396 int totlen;
7397 int len;
7398 struct asc_stats *s;
7399 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007400
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007401 leftlen = cplen;
7402 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007403
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007404 boardp = ASC_BOARDP(shost);
7405 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007406
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007407 len = asc_prt_line(cp, leftlen,
7408 "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
7409 shost->host_no);
7410 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007411
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007412 len = asc_prt_line(cp, leftlen,
7413 " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
7414 s->queuecommand, s->reset, s->biosparam,
7415 s->interrupt);
7416 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007417
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007418 len = asc_prt_line(cp, leftlen,
7419 " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
7420 s->callback, s->done, s->build_error,
7421 s->adv_build_noreq, s->adv_build_nosg);
7422 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007423
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007424 len = asc_prt_line(cp, leftlen,
7425 " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
7426 s->exe_noerror, s->exe_busy, s->exe_error,
7427 s->exe_unknown);
7428 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007429
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007430 /*
7431 * Display data transfer statistics.
7432 */
7433 if (s->cont_cnt > 0) {
7434 len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
7435 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007436
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007437 len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
7438 s->cont_xfer / 2,
7439 ASC_TENTHS(s->cont_xfer, 2));
7440 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007441
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007442 /* Contiguous transfer average size */
7443 len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
7444 (s->cont_xfer / 2) / s->cont_cnt,
7445 ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
7446 ASC_PRT_NEXT();
7447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007448
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007449 if (s->sg_cnt > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007450
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007451 len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
7452 s->sg_cnt, s->sg_elem);
7453 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007454
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007455 len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
7456 s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
7457 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007458
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007459 /* Scatter gather transfer statistics */
7460 len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
7461 s->sg_elem / s->sg_cnt,
7462 ASC_TENTHS(s->sg_elem, s->sg_cnt));
7463 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007464
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007465 len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
7466 (s->sg_xfer / 2) / s->sg_elem,
7467 ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
7468 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007469
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007470 len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
7471 (s->sg_xfer / 2) / s->sg_cnt,
7472 ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
7473 ASC_PRT_NEXT();
7474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007475
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007476 /*
7477 * Display request queuing statistics.
7478 */
7479 len = asc_prt_line(cp, leftlen,
7480 " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
7481 HZ);
7482 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007483
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007484 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007485}
7486
7487/*
7488 * asc_prt_target_stats()
7489 *
7490 * Note: no single line should be greater than ASC_PRTLINE_SIZE,
7491 * cf. asc_prt_line().
7492 *
7493 * This is separated from asc_prt_board_stats because a full set
7494 * of targets will overflow ASC_PRTBUF_SIZE.
7495 *
7496 * Return the number of characters copied into 'cp'. No more than
7497 * 'cplen' characters will be copied to 'cp'.
7498 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007499static int
7500asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007501{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007502 int leftlen;
7503 int totlen;
7504 int len;
7505 struct asc_stats *s;
7506 ushort chip_scsi_id;
7507 asc_board_t *boardp;
7508 asc_queue_t *active;
7509 asc_queue_t *waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007510
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007511 leftlen = cplen;
7512 totlen = len = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007513
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007514 boardp = ASC_BOARDP(shost);
7515 s = &boardp->asc_stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007516
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007517 active = &ASC_BOARDP(shost)->active;
7518 waiting = &ASC_BOARDP(shost)->waiting;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007519
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007520 if (ASC_NARROW_BOARD(boardp)) {
7521 chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
7522 } else {
7523 chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
7524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007525
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007526 if ((chip_scsi_id == tgt_id) ||
7527 ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
7528 return 0;
7529 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007530
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007531 do {
7532 if (active->q_tot_cnt[tgt_id] > 0
7533 || waiting->q_tot_cnt[tgt_id] > 0) {
7534 len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
7535 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007536
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007537 len = asc_prt_line(cp, leftlen,
7538 " active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
7539 active->q_cur_cnt[tgt_id],
7540 active->q_max_cnt[tgt_id],
7541 active->q_tot_cnt[tgt_id],
7542 active->q_min_tim[tgt_id],
7543 active->q_max_tim[tgt_id],
7544 (active->q_tot_cnt[tgt_id] ==
7545 0) ? 0 : (active->
7546 q_tot_tim[tgt_id] /
7547 active->
7548 q_tot_cnt[tgt_id]),
7549 (active->q_tot_cnt[tgt_id] ==
7550 0) ? 0 : ASC_TENTHS(active->
7551 q_tot_tim
7552 [tgt_id],
7553 active->
7554 q_tot_cnt
7555 [tgt_id]));
7556 ASC_PRT_NEXT();
Linus Torvalds1da177e2005-04-16 15:20:36 -07007557
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007558 len = asc_prt_line(cp, leftlen,
7559 " waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
7560 waiting->q_cur_cnt[tgt_id],
7561 waiting->q_max_cnt[tgt_id],
7562 waiting->q_tot_cnt[tgt_id],
7563 waiting->q_min_tim[tgt_id],
7564 waiting->q_max_tim[tgt_id],
7565 (waiting->q_tot_cnt[tgt_id] ==
7566 0) ? 0 : (waiting->
7567 q_tot_tim[tgt_id] /
7568 waiting->
7569 q_tot_cnt[tgt_id]),
7570 (waiting->q_tot_cnt[tgt_id] ==
7571 0) ? 0 : ASC_TENTHS(waiting->
7572 q_tot_tim
7573 [tgt_id],
7574 waiting->
7575 q_tot_cnt
7576 [tgt_id]));
7577 ASC_PRT_NEXT();
7578 }
7579 } while (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007580
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007581 return totlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007582}
7583#endif /* CONFIG_PROC_FS */
7584#endif /* ADVANSYS_STATS */
7585
7586#ifdef ADVANSYS_DEBUG
7587/*
7588 * asc_prt_scsi_host()
7589 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007590static void asc_prt_scsi_host(struct Scsi_Host *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007591{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007592 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007593
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007594 boardp = ASC_BOARDP(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007595
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007596 printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
7597 printk(" host_busy %u, host_no %d, last_reset %d,\n",
7598 s->host_busy, s->host_no, (unsigned)s->last_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007599
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007600 printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
7601 (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007602
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007603 printk(" dma_channel %d, this_id %d, can_queue %d,\n",
7604 s->dma_channel, s->this_id, s->can_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007605
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007606 printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
7607 s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007608
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007609 if (ASC_NARROW_BOARD(boardp)) {
7610 asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
7611 asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
7612 } else {
7613 asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
7614 asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
7615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007616}
7617
7618/*
7619 * asc_prt_scsi_cmnd()
7620 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007621static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007622{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007623 printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007624
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007625 printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
7626 (ulong)s->device->host, (ulong)s->device, s->device->id,
7627 s->device->lun, s->device->channel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007628
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007629 asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007630
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007631 printk("sc_data_direction %u, resid %d\n",
7632 s->sc_data_direction, s->resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007633
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007634 printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007635
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007636 printk(" serial_number 0x%x, retries %d, allowed %d\n",
7637 (unsigned)s->serial_number, s->retries, s->allowed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007638
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007639 printk(" timeout_per_command %d\n", s->timeout_per_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007640
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007641 printk
7642 (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
7643 (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble,
7644 s->result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007645
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007646 printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007647}
7648
7649/*
7650 * asc_prt_asc_dvc_var()
7651 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007652static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007653{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007654 printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007655
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007656 printk
7657 (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
7658 h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007659
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007660 printk
7661 (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
7662 h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback,
7663 (unsigned)h->init_sdtr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007664
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007665 printk
7666 (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
7667 (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng,
7668 (unsigned)h->unit_not_ready, (unsigned)h->chip_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007669
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007670 printk
7671 (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
7672 (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor,
7673 (unsigned)h->scsi_reset_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007674
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007675 printk
7676 (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
7677 (unsigned)h->is_in_int, (unsigned)h->max_total_qng,
7678 (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007679
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007680 printk
7681 (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
7682 (unsigned)h->last_q_shortage, (unsigned)h->init_state,
7683 (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007684
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007685 printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007686}
7687
7688/*
7689 * asc_prt_asc_dvc_cfg()
7690 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007691static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007692{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007693 printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007694
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007695 printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
7696 h->can_tagged_qng, h->cmd_qng_enabled);
7697 printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
7698 h->disc_enable, h->sdtr_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007699
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007700 printk
7701 (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
7702 h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
7703 h->chip_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007704
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007705 printk
7706 (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
7707 to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
7708 h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007709
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007710 printk(" mcode_version %d, overrun_buf 0x%lx\n",
7711 h->mcode_version, (ulong)h->overrun_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007712}
7713
7714/*
7715 * asc_prt_asc_scsi_q()
7716 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007717static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007718{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007719 ASC_SG_HEAD *sgp;
7720 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007721
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007722 printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007723
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007724 printk
7725 (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
7726 q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
7727 q->q2.tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007728
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007729 printk
7730 (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7731 (ulong)le32_to_cpu(q->q1.data_addr),
7732 (ulong)le32_to_cpu(q->q1.data_cnt),
7733 (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007734
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007735 printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
7736 (ulong)q->cdbptr, q->q2.cdb_len,
7737 (ulong)q->sg_head, q->q1.sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007738
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007739 if (q->sg_head) {
7740 sgp = q->sg_head;
7741 printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
7742 printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
7743 sgp->queue_cnt);
7744 for (i = 0; i < sgp->entry_cnt; i++) {
7745 printk(" [%u]: addr 0x%lx, bytes %lu\n",
7746 i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
7747 (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
7748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007749
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007751}
7752
7753/*
7754 * asc_prt_asc_qdone_info()
7755 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007756static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007757{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007758 printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
7759 printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
7760 (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
7761 q->d2.tag_code);
7762 printk
7763 (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
7764 q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007765}
7766
7767/*
7768 * asc_prt_adv_dvc_var()
7769 *
7770 * Display an ADV_DVC_VAR structure.
7771 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007772static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007773{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007774 printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007775
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007776 printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
7777 (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007778
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007779 printk(" isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
7780 (ulong)h->isr_callback, (unsigned)h->sdtr_able,
7781 (unsigned)h->wdtr_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007782
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007783 printk(" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
7784 (unsigned)h->start_motor,
7785 (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007786
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007787 printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
7788 (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
7789 (ulong)h->carr_freelist);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007790
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007791 printk(" icq_sp 0x%lx, irq_sp 0x%lx\n",
7792 (ulong)h->icq_sp, (ulong)h->irq_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007793
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007794 printk(" no_scam 0x%x, tagqng_able 0x%x\n",
7795 (unsigned)h->no_scam, (unsigned)h->tagqng_able);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007796
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007797 printk(" chip_scsi_id 0x%x, cfg 0x%lx\n",
7798 (unsigned)h->chip_scsi_id, (ulong)h->cfg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007799}
7800
7801/*
7802 * asc_prt_adv_dvc_cfg()
7803 *
7804 * Display an ADV_DVC_CFG structure.
7805 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007806static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007807{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007808 printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007809
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007810 printk(" disc_enable 0x%x, termination 0x%x\n",
7811 h->disc_enable, h->termination);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007812
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007813 printk(" chip_version 0x%x, mcode_date 0x%x\n",
7814 h->chip_version, h->mcode_date);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007815
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007816 printk(" mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
7817 h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007818
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007819 printk(" control_flag 0x%x, pci_slot_info 0x%x\n",
7820 h->control_flag, h->pci_slot_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007821}
7822
7823/*
7824 * asc_prt_adv_scsi_req_q()
7825 *
7826 * Display an ADV_SCSI_REQ_Q structure.
7827 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007828static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007829{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007830 int sg_blk_cnt;
7831 struct asc_sg_block *sg_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007832
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007833 printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007834
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007835 printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
7836 q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007837
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007838 printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
7839 q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007840
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007841 printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
7842 (ulong)le32_to_cpu(q->data_cnt),
7843 (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007844
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007845 printk
7846 (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
7847 q->cdb_len, q->done_status, q->host_status, q->scsi_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007848
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007849 printk(" sg_working_ix 0x%x, target_cmd %u\n",
7850 q->sg_working_ix, q->target_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007851
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007852 printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
7853 (ulong)le32_to_cpu(q->scsiq_rptr),
7854 (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007855
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007856 /* Display the request's ADV_SG_BLOCK structures. */
7857 if (q->sg_list_ptr != NULL) {
7858 sg_blk_cnt = 0;
7859 while (1) {
7860 /*
7861 * 'sg_ptr' is a physical address. Convert it to a virtual
7862 * address by indexing 'sg_blk_cnt' into the virtual address
7863 * array 'sg_list_ptr'.
7864 *
7865 * XXX - Assumes all SG physical blocks are virtually contiguous.
7866 */
7867 sg_ptr =
7868 &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
7869 asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
7870 if (sg_ptr->sg_ptr == 0) {
7871 break;
7872 }
7873 sg_blk_cnt++;
7874 }
7875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007876}
7877
7878/*
7879 * asc_prt_adv_sgblock()
7880 *
7881 * Display an ADV_SG_BLOCK structure.
7882 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007883static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007884{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007885 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007887 printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
7888 (ulong)b, sgblockno);
7889 printk(" sg_cnt %u, sg_ptr 0x%lx\n",
7890 b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
7891 ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
7892 if (b->sg_ptr != 0) {
7893 ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
7894 }
7895 for (i = 0; i < b->sg_cnt; i++) {
7896 printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
7897 i, (ulong)b->sg_list[i].sg_addr,
7898 (ulong)b->sg_list[i].sg_count);
7899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007900}
7901
7902/*
7903 * asc_prt_hex()
7904 *
7905 * Print hexadecimal output in 4 byte groupings 32 bytes
7906 * or 8 double-words per line.
7907 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007908static void asc_prt_hex(char *f, uchar *s, int l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007909{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007910 int i;
7911 int j;
7912 int k;
7913 int m;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007914
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007915 printk("%s: (%d bytes)\n", f, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007916
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007917 for (i = 0; i < l; i += 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007918
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007919 /* Display a maximum of 8 double-words per line. */
7920 if ((k = (l - i) / 4) >= 8) {
7921 k = 8;
7922 m = 0;
7923 } else {
7924 m = (l - i) % 4;
7925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007926
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007927 for (j = 0; j < k; j++) {
7928 printk(" %2.2X%2.2X%2.2X%2.2X",
7929 (unsigned)s[i + (j * 4)],
7930 (unsigned)s[i + (j * 4) + 1],
7931 (unsigned)s[i + (j * 4) + 2],
7932 (unsigned)s[i + (j * 4) + 3]);
7933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007934
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007935 switch (m) {
7936 case 0:
7937 default:
7938 break;
7939 case 1:
7940 printk(" %2.2X", (unsigned)s[i + (j * 4)]);
7941 break;
7942 case 2:
7943 printk(" %2.2X%2.2X",
7944 (unsigned)s[i + (j * 4)],
7945 (unsigned)s[i + (j * 4) + 1]);
7946 break;
7947 case 3:
7948 printk(" %2.2X%2.2X%2.2X",
7949 (unsigned)s[i + (j * 4) + 1],
7950 (unsigned)s[i + (j * 4) + 2],
7951 (unsigned)s[i + (j * 4) + 3]);
7952 break;
7953 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007954
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007955 printk("\n");
7956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007957}
7958#endif /* ADVANSYS_DEBUG */
7959
7960/*
7961 * --- Asc Library Functions
7962 */
7963
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007964static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007965{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007966 PortAddr eisa_cfg_iop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007967
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007968 eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
7969 (PortAddr) (ASC_EISA_CFG_IOP_MASK);
7970 return (inpw(eisa_cfg_iop));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007971}
7972
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007973static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007974{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007975 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007976
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007977 if (AscGetChipScsiID(iop_base) == new_host_id) {
7978 return (new_host_id);
7979 }
7980 cfg_lsw = AscGetChipCfgLsw(iop_base);
7981 cfg_lsw &= 0xF8FF;
7982 cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
7983 AscSetChipCfgLsw(iop_base, cfg_lsw);
7984 return (AscGetChipScsiID(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07007985}
7986
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007987static uchar __devinit AscGetChipScsiCtrl(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007988{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007989 uchar sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007990
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007991 AscSetBank(iop_base, 1);
7992 sc = inp(iop_base + IOP_REG_SC);
7993 AscSetBank(iop_base, 0);
7994 return (sc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007995}
7996
Matthew Wilcox78e77d82007-07-29 21:46:15 -06007997static uchar __devinit AscGetChipVersion(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07007998{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04007999 if ((bus_type & ASC_IS_EISA) != 0) {
8000 PortAddr eisa_iop;
8001 uchar revision;
8002 eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
8003 (PortAddr) ASC_EISA_REV_IOP_MASK;
8004 revision = inp(eisa_iop);
8005 return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision));
8006 }
8007 return (AscGetChipVerNo(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008008}
8009
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008010static ushort __devinit AscGetChipBusType(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008011{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008012 ushort chip_ver;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008013
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008014 chip_ver = AscGetChipVerNo(iop_base);
8015 if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
8016 && (chip_ver <= ASC_CHIP_MAX_VER_VL)
8017 ) {
8018 if (((iop_base & 0x0C30) == 0x0C30)
8019 || ((iop_base & 0x0C50) == 0x0C50)
8020 ) {
8021 return (ASC_IS_EISA);
8022 }
8023 return (ASC_IS_VL);
8024 }
8025 if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
8026 (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
8027 if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
8028 return (ASC_IS_ISAPNP);
8029 }
8030 return (ASC_IS_ISA);
8031 } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
8032 (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
8033 return (ASC_IS_PCI);
8034 }
8035 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008036}
8037
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008038static ASC_DCNT
8039AscLoadMicroCode(PortAddr iop_base,
8040 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008041{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008042 ASC_DCNT chksum;
8043 ushort mcode_word_size;
8044 ushort mcode_chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008045
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008046 /* Write the microcode buffer starting at LRAM address 0. */
8047 mcode_word_size = (ushort)(mcode_size >> 1);
8048 AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
8049 AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008050
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008051 chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
8052 ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
8053 mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
8054 (ushort)ASC_CODE_SEC_BEG,
8055 (ushort)((mcode_size -
8056 s_addr - (ushort)
8057 ASC_CODE_SEC_BEG) /
8058 2));
8059 ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
8060 (ulong)mcode_chksum);
8061 AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
8062 AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
8063 return (chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008064}
8065
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008066static int AscFindSignature(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008067{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008068 ushort sig_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008069
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008070 ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
8071 iop_base, AscGetChipSignatureByte(iop_base));
8072 if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
8073 ASC_DBG2(1,
8074 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
8075 iop_base, AscGetChipSignatureWord(iop_base));
8076 sig_word = AscGetChipSignatureWord(iop_base);
8077 if ((sig_word == (ushort)ASC_1000_ID0W) ||
8078 (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
8079 return (1);
8080 }
8081 }
8082 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008083}
8084
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008085static void __devinit AscToggleIRQAct(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008086{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008087 AscSetChipStatus(iop_base, CIW_IRQ_ACT);
8088 AscSetChipStatus(iop_base, 0);
8089 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008090}
8091
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008092static uchar __devinit AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008093{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008094 ushort cfg_lsw;
8095 uchar chip_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008096
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008097 if ((bus_type & ASC_IS_EISA) != 0) {
8098 cfg_lsw = AscGetEisaChipCfg(iop_base);
8099 chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
8100 if ((chip_irq == 13) || (chip_irq > 15)) {
8101 return (0);
8102 }
8103 return (chip_irq);
8104 }
8105 if ((bus_type & ASC_IS_VL) != 0) {
8106 cfg_lsw = AscGetChipCfgLsw(iop_base);
8107 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
8108 if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
8109 return (0);
8110 }
8111 return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
8112 }
8113 cfg_lsw = AscGetChipCfgLsw(iop_base);
8114 chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
8115 if (chip_irq == 3)
8116 chip_irq += (uchar)2;
8117 return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008118}
8119
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008120static uchar __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008121AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008122{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008123 ushort cfg_lsw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008124
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008125 if ((bus_type & ASC_IS_VL) != 0) {
8126 if (irq_no != 0) {
8127 if ((irq_no < ASC_MIN_IRQ_NO)
8128 || (irq_no > ASC_MAX_IRQ_NO)) {
8129 irq_no = 0;
8130 } else {
8131 irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
8132 }
8133 }
8134 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
8135 cfg_lsw |= (ushort)0x0010;
8136 AscSetChipCfgLsw(iop_base, cfg_lsw);
8137 AscToggleIRQAct(iop_base);
8138 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
8139 cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
8140 AscSetChipCfgLsw(iop_base, cfg_lsw);
8141 AscToggleIRQAct(iop_base);
8142 return (AscGetChipIRQ(iop_base, bus_type));
8143 }
8144 if ((bus_type & (ASC_IS_ISA)) != 0) {
8145 if (irq_no == 15)
8146 irq_no -= (uchar)2;
8147 irq_no -= (uchar)ASC_MIN_IRQ_NO;
8148 cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
8149 cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
8150 AscSetChipCfgLsw(iop_base, cfg_lsw);
8151 return (AscGetChipIRQ(iop_base, bus_type));
8152 }
8153 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008154}
8155
8156#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -06008157static void __devinit AscEnableIsaDma(uchar dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008158{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008159 if (dma_channel < 4) {
8160 outp(0x000B, (ushort)(0xC0 | dma_channel));
8161 outp(0x000A, dma_channel);
8162 } else if (dma_channel < 8) {
8163 outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
8164 outp(0x00D4, (ushort)(dma_channel - 4));
8165 }
8166 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008167}
8168#endif /* CONFIG_ISA */
8169
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008170static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008171{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008172 EXT_MSG ext_msg;
8173 EXT_MSG out_msg;
8174 ushort halt_q_addr;
8175 int sdtr_accept;
8176 ushort int_halt_code;
8177 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8178 ASC_SCSI_BIT_ID_TYPE target_id;
8179 PortAddr iop_base;
8180 uchar tag_code;
8181 uchar q_status;
8182 uchar halt_qp;
8183 uchar sdtr_data;
8184 uchar target_ix;
8185 uchar q_cntl, tid_no;
8186 uchar cur_dvc_qng;
8187 uchar asyn_sdtr;
8188 uchar scsi_status;
8189 asc_board_t *boardp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008190
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008191 ASC_ASSERT(asc_dvc->drv_ptr != NULL);
8192 boardp = asc_dvc->drv_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008193
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008194 iop_base = asc_dvc->iop_base;
8195 int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008196
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008197 halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
8198 halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
8199 target_ix = AscReadLramByte(iop_base,
8200 (ushort)(halt_q_addr +
8201 (ushort)ASC_SCSIQ_B_TARGET_IX));
8202 q_cntl =
8203 AscReadLramByte(iop_base,
8204 (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8205 tid_no = ASC_TIX_TO_TID(target_ix);
8206 target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
8207 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8208 asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
8209 } else {
8210 asyn_sdtr = 0;
8211 }
8212 if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
8213 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8214 AscSetChipSDTR(iop_base, 0, tid_no);
8215 boardp->sdtr_data[tid_no] = 0;
8216 }
8217 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8218 return (0);
8219 } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
8220 if (asc_dvc->pci_fix_asyn_xfer & target_id) {
8221 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8222 boardp->sdtr_data[tid_no] = asyn_sdtr;
8223 }
8224 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8225 return (0);
8226 } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008227
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008228 AscMemWordCopyPtrFromLram(iop_base,
8229 ASCV_MSGIN_BEG,
8230 (uchar *)&ext_msg,
8231 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008232
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008233 if (ext_msg.msg_type == MS_EXTEND &&
8234 ext_msg.msg_req == MS_SDTR_CODE &&
8235 ext_msg.msg_len == MS_SDTR_LEN) {
8236 sdtr_accept = TRUE;
8237 if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008238
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008239 sdtr_accept = FALSE;
8240 ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
8241 }
8242 if ((ext_msg.xfer_period <
8243 asc_dvc->sdtr_period_tbl[asc_dvc->
8244 host_init_sdtr_index])
8245 || (ext_msg.xfer_period >
8246 asc_dvc->sdtr_period_tbl[asc_dvc->
8247 max_sdtr_index])) {
8248 sdtr_accept = FALSE;
8249 ext_msg.xfer_period =
8250 asc_dvc->sdtr_period_tbl[asc_dvc->
8251 host_init_sdtr_index];
8252 }
8253 if (sdtr_accept) {
8254 sdtr_data =
8255 AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
8256 ext_msg.req_ack_offset);
8257 if ((sdtr_data == 0xFF)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008258
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008259 q_cntl |= QC_MSG_OUT;
8260 asc_dvc->init_sdtr &= ~target_id;
8261 asc_dvc->sdtr_done &= ~target_id;
8262 AscSetChipSDTR(iop_base, asyn_sdtr,
8263 tid_no);
8264 boardp->sdtr_data[tid_no] = asyn_sdtr;
8265 }
8266 }
8267 if (ext_msg.req_ack_offset == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008268
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008269 q_cntl &= ~QC_MSG_OUT;
8270 asc_dvc->init_sdtr &= ~target_id;
8271 asc_dvc->sdtr_done &= ~target_id;
8272 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8273 } else {
8274 if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008275
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008276 q_cntl &= ~QC_MSG_OUT;
8277 asc_dvc->sdtr_done |= target_id;
8278 asc_dvc->init_sdtr |= target_id;
8279 asc_dvc->pci_fix_asyn_xfer &=
8280 ~target_id;
8281 sdtr_data =
8282 AscCalSDTRData(asc_dvc,
8283 ext_msg.xfer_period,
8284 ext_msg.
8285 req_ack_offset);
8286 AscSetChipSDTR(iop_base, sdtr_data,
8287 tid_no);
8288 boardp->sdtr_data[tid_no] = sdtr_data;
8289 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008290
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008291 q_cntl |= QC_MSG_OUT;
8292 AscMsgOutSDTR(asc_dvc,
8293 ext_msg.xfer_period,
8294 ext_msg.req_ack_offset);
8295 asc_dvc->pci_fix_asyn_xfer &=
8296 ~target_id;
8297 sdtr_data =
8298 AscCalSDTRData(asc_dvc,
8299 ext_msg.xfer_period,
8300 ext_msg.
8301 req_ack_offset);
8302 AscSetChipSDTR(iop_base, sdtr_data,
8303 tid_no);
8304 boardp->sdtr_data[tid_no] = sdtr_data;
8305 asc_dvc->sdtr_done |= target_id;
8306 asc_dvc->init_sdtr |= target_id;
8307 }
8308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008309
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008310 AscWriteLramByte(iop_base,
8311 (ushort)(halt_q_addr +
8312 (ushort)ASC_SCSIQ_B_CNTL),
8313 q_cntl);
8314 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8315 return (0);
8316 } else if (ext_msg.msg_type == MS_EXTEND &&
8317 ext_msg.msg_req == MS_WDTR_CODE &&
8318 ext_msg.msg_len == MS_WDTR_LEN) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008319
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008320 ext_msg.wdtr_width = 0;
8321 AscMemWordCopyPtrToLram(iop_base,
8322 ASCV_MSGOUT_BEG,
8323 (uchar *)&ext_msg,
8324 sizeof(EXT_MSG) >> 1);
8325 q_cntl |= QC_MSG_OUT;
8326 AscWriteLramByte(iop_base,
8327 (ushort)(halt_q_addr +
8328 (ushort)ASC_SCSIQ_B_CNTL),
8329 q_cntl);
8330 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8331 return (0);
8332 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008333
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008334 ext_msg.msg_type = MESSAGE_REJECT;
8335 AscMemWordCopyPtrToLram(iop_base,
8336 ASCV_MSGOUT_BEG,
8337 (uchar *)&ext_msg,
8338 sizeof(EXT_MSG) >> 1);
8339 q_cntl |= QC_MSG_OUT;
8340 AscWriteLramByte(iop_base,
8341 (ushort)(halt_q_addr +
8342 (ushort)ASC_SCSIQ_B_CNTL),
8343 q_cntl);
8344 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8345 return (0);
8346 }
8347 } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008348
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008349 q_cntl |= QC_REQ_SENSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008350
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008351 if ((asc_dvc->init_sdtr & target_id) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008352
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008353 asc_dvc->sdtr_done &= ~target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008354
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008355 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
8356 q_cntl |= QC_MSG_OUT;
8357 AscMsgOutSDTR(asc_dvc,
8358 asc_dvc->
8359 sdtr_period_tbl[(sdtr_data >> 4) &
8360 (uchar)(asc_dvc->
8361 max_sdtr_index -
8362 1)],
8363 (uchar)(sdtr_data & (uchar)
8364 ASC_SYN_MAX_OFFSET));
8365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008366
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008367 AscWriteLramByte(iop_base,
8368 (ushort)(halt_q_addr +
8369 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008370
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008371 tag_code = AscReadLramByte(iop_base,
8372 (ushort)(halt_q_addr + (ushort)
8373 ASC_SCSIQ_B_TAG_CODE));
8374 tag_code &= 0xDC;
8375 if ((asc_dvc->pci_fix_asyn_xfer & target_id)
8376 && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
8377 ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008378
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008379 tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
8380 | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008381
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008382 }
8383 AscWriteLramByte(iop_base,
8384 (ushort)(halt_q_addr +
8385 (ushort)ASC_SCSIQ_B_TAG_CODE),
8386 tag_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008387
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008388 q_status = AscReadLramByte(iop_base,
8389 (ushort)(halt_q_addr + (ushort)
8390 ASC_SCSIQ_B_STATUS));
8391 q_status |= (QS_READY | QS_BUSY);
8392 AscWriteLramByte(iop_base,
8393 (ushort)(halt_q_addr +
8394 (ushort)ASC_SCSIQ_B_STATUS),
8395 q_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008396
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008397 scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
8398 scsi_busy &= ~target_id;
8399 AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008400
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008401 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8402 return (0);
8403 } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008404
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008405 AscMemWordCopyPtrFromLram(iop_base,
8406 ASCV_MSGOUT_BEG,
8407 (uchar *)&out_msg,
8408 sizeof(EXT_MSG) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008409
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008410 if ((out_msg.msg_type == MS_EXTEND) &&
8411 (out_msg.msg_len == MS_SDTR_LEN) &&
8412 (out_msg.msg_req == MS_SDTR_CODE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008413
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008414 asc_dvc->init_sdtr &= ~target_id;
8415 asc_dvc->sdtr_done &= ~target_id;
8416 AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
8417 boardp->sdtr_data[tid_no] = asyn_sdtr;
8418 }
8419 q_cntl &= ~QC_MSG_OUT;
8420 AscWriteLramByte(iop_base,
8421 (ushort)(halt_q_addr +
8422 (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
8423 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8424 return (0);
8425 } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008426
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008427 scsi_status = AscReadLramByte(iop_base,
8428 (ushort)((ushort)halt_q_addr +
8429 (ushort)
8430 ASC_SCSIQ_SCSI_STATUS));
8431 cur_dvc_qng =
8432 AscReadLramByte(iop_base,
8433 (ushort)((ushort)ASC_QADR_BEG +
8434 (ushort)target_ix));
8435 if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07008436
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008437 scsi_busy = AscReadLramByte(iop_base,
8438 (ushort)ASCV_SCSIBUSY_B);
8439 scsi_busy |= target_id;
8440 AscWriteLramByte(iop_base,
8441 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
8442 asc_dvc->queue_full_or_busy |= target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008443
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008444 if (scsi_status == SAM_STAT_TASK_SET_FULL) {
8445 if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
8446 cur_dvc_qng -= 1;
8447 asc_dvc->max_dvc_qng[tid_no] =
8448 cur_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008449
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008450 AscWriteLramByte(iop_base,
8451 (ushort)((ushort)
8452 ASCV_MAX_DVC_QNG_BEG
8453 + (ushort)
8454 tid_no),
8455 cur_dvc_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008456
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008457 /*
8458 * Set the device queue depth to the number of
8459 * active requests when the QUEUE FULL condition
8460 * was encountered.
8461 */
8462 boardp->queue_full |= target_id;
8463 boardp->queue_full_cnt[tid_no] =
8464 cur_dvc_qng;
8465 }
8466 }
8467 }
8468 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8469 return (0);
8470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008471#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008472 else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
8473 uchar q_no;
8474 ushort q_addr;
8475 uchar sg_wk_q_no;
8476 uchar first_sg_wk_q_no;
8477 ASC_SCSI_Q *scsiq; /* Ptr to driver request. */
8478 ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */
8479 ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */
8480 ushort sg_list_dwords;
8481 ushort sg_entry_cnt;
8482 uchar next_qp;
8483 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008484
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008485 q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
8486 if (q_no == ASC_QLINK_END) {
8487 return (0);
8488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008489
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008490 q_addr = ASC_QNO_TO_QADDR(q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008491
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008492 /*
8493 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
8494 * structure pointer using a macro provided by the driver.
8495 * The ASC_SCSI_REQ pointer provides a pointer to the
8496 * host ASC_SG_HEAD structure.
8497 */
8498 /* Read request's SRB pointer. */
8499 scsiq = (ASC_SCSI_Q *)
8500 ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
8501 (ushort)
8502 (q_addr +
8503 ASC_SCSIQ_D_SRBPTR))));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008504
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008505 /*
8506 * Get request's first and working SG queue.
8507 */
8508 sg_wk_q_no = AscReadLramByte(iop_base,
8509 (ushort)(q_addr +
8510 ASC_SCSIQ_B_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008511
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008512 first_sg_wk_q_no = AscReadLramByte(iop_base,
8513 (ushort)(q_addr +
8514 ASC_SCSIQ_B_FIRST_SG_WK_QP));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008515
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008516 /*
8517 * Reset request's working SG queue back to the
8518 * first SG queue.
8519 */
8520 AscWriteLramByte(iop_base,
8521 (ushort)(q_addr +
8522 (ushort)ASC_SCSIQ_B_SG_WK_QP),
8523 first_sg_wk_q_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008524
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008525 sg_head = scsiq->sg_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008526
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008527 /*
8528 * Set sg_entry_cnt to the number of SG elements
8529 * that will be completed on this interrupt.
8530 *
8531 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
8532 * SG elements. The data_cnt and data_addr fields which
8533 * add 1 to the SG element capacity are not used when
8534 * restarting SG handling after a halt.
8535 */
8536 if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
8537 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008538
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008539 /*
8540 * Keep track of remaining number of SG elements that will
8541 * need to be handled on the next interrupt.
8542 */
8543 scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
8544 } else {
8545 sg_entry_cnt = scsiq->remain_sg_entry_cnt;
8546 scsiq->remain_sg_entry_cnt = 0;
8547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008548
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008549 /*
8550 * Copy SG elements into the list of allocated SG queues.
8551 *
8552 * Last index completed is saved in scsiq->next_sg_index.
8553 */
8554 next_qp = first_sg_wk_q_no;
8555 q_addr = ASC_QNO_TO_QADDR(next_qp);
8556 scsi_sg_q.sg_head_qp = q_no;
8557 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
8558 for (i = 0; i < sg_head->queue_cnt; i++) {
8559 scsi_sg_q.seq_no = i + 1;
8560 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
8561 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
8562 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
8563 /*
8564 * After very first SG queue RISC FW uses next
8565 * SG queue first element then checks sg_list_cnt
8566 * against zero and then decrements, so set
8567 * sg_list_cnt 1 less than number of SG elements
8568 * in each SG queue.
8569 */
8570 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
8571 scsi_sg_q.sg_cur_list_cnt =
8572 ASC_SG_LIST_PER_Q - 1;
8573 } else {
8574 /*
8575 * This is the last SG queue in the list of
8576 * allocated SG queues. If there are more
8577 * SG elements than will fit in the allocated
8578 * queues, then set the QCSG_SG_XFER_MORE flag.
8579 */
8580 if (scsiq->remain_sg_entry_cnt != 0) {
8581 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
8582 } else {
8583 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
8584 }
8585 /* equals sg_entry_cnt * 2 */
8586 sg_list_dwords = sg_entry_cnt << 1;
8587 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
8588 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
8589 sg_entry_cnt = 0;
8590 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008591
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008592 scsi_sg_q.q_no = next_qp;
8593 AscMemWordCopyPtrToLram(iop_base,
8594 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
8595 (uchar *)&scsi_sg_q,
8596 sizeof(ASC_SG_LIST_Q) >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008597
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008598 AscMemDWordCopyPtrToLram(iop_base,
8599 q_addr + ASC_SGQ_LIST_BEG,
8600 (uchar *)&sg_head->
8601 sg_list[scsiq->next_sg_index],
8602 sg_list_dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008603
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008604 scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008605
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008606 /*
8607 * If the just completed SG queue contained the
8608 * last SG element, then no more SG queues need
8609 * to be written.
8610 */
8611 if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
8612 break;
8613 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008614
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008615 next_qp = AscReadLramByte(iop_base,
8616 (ushort)(q_addr +
8617 ASC_SCSIQ_B_FWD));
8618 q_addr = ASC_QNO_TO_QADDR(next_qp);
8619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008620
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008621 /*
8622 * Clear the halt condition so the RISC will be restarted
8623 * after the return.
8624 */
8625 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
8626 return (0);
8627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008628#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008629 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008630}
8631
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008632static uchar
8633_AscCopyLramScsiDoneQ(PortAddr iop_base,
8634 ushort q_addr,
8635 ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008636{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008637 ushort _val;
8638 uchar sg_queue_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008639
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008640 DvcGetQinfo(iop_base,
8641 q_addr + ASC_SCSIQ_DONE_INFO_BEG,
8642 (uchar *)scsiq,
8643 (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008644
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008645 _val = AscReadLramWord(iop_base,
8646 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
8647 scsiq->q_status = (uchar)_val;
8648 scsiq->q_no = (uchar)(_val >> 8);
8649 _val = AscReadLramWord(iop_base,
8650 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
8651 scsiq->cntl = (uchar)_val;
8652 sg_queue_cnt = (uchar)(_val >> 8);
8653 _val = AscReadLramWord(iop_base,
8654 (ushort)(q_addr +
8655 (ushort)ASC_SCSIQ_B_SENSE_LEN));
8656 scsiq->sense_len = (uchar)_val;
8657 scsiq->extra_bytes = (uchar)(_val >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008658
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008659 /*
8660 * Read high word of remain bytes from alternate location.
8661 */
8662 scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
8663 (ushort)(q_addr +
8664 (ushort)
8665 ASC_SCSIQ_W_ALT_DC1)))
8666 << 16);
8667 /*
8668 * Read low word of remain bytes from original location.
8669 */
8670 scsiq->remain_bytes += AscReadLramWord(iop_base,
8671 (ushort)(q_addr + (ushort)
8672 ASC_SCSIQ_DW_REMAIN_XFER_CNT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07008673
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008674 scsiq->remain_bytes &= max_dma_count;
8675 return (sg_queue_cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008676}
8677
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008678static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008679{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008680 uchar next_qp;
8681 uchar n_q_used;
8682 uchar sg_list_qp;
8683 uchar sg_queue_cnt;
8684 uchar q_cnt;
8685 uchar done_q_tail;
8686 uchar tid_no;
8687 ASC_SCSI_BIT_ID_TYPE scsi_busy;
8688 ASC_SCSI_BIT_ID_TYPE target_id;
8689 PortAddr iop_base;
8690 ushort q_addr;
8691 ushort sg_q_addr;
8692 uchar cur_target_qng;
8693 ASC_QDONE_INFO scsiq_buf;
8694 ASC_QDONE_INFO *scsiq;
8695 int false_overrun;
8696 ASC_ISR_CALLBACK asc_isr_callback;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008697
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008698 iop_base = asc_dvc->iop_base;
8699 asc_isr_callback = asc_dvc->isr_callback;
8700 n_q_used = 1;
8701 scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
8702 done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
8703 q_addr = ASC_QNO_TO_QADDR(done_q_tail);
8704 next_qp = AscReadLramByte(iop_base,
8705 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
8706 if (next_qp != ASC_QLINK_END) {
8707 AscPutVarDoneQTail(iop_base, next_qp);
8708 q_addr = ASC_QNO_TO_QADDR(next_qp);
8709 sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
8710 asc_dvc->max_dma_count);
8711 AscWriteLramByte(iop_base,
8712 (ushort)(q_addr +
8713 (ushort)ASC_SCSIQ_B_STATUS),
8714 (uchar)(scsiq->
8715 q_status & (uchar)~(QS_READY |
8716 QS_ABORTED)));
8717 tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
8718 target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
8719 if ((scsiq->cntl & QC_SG_HEAD) != 0) {
8720 sg_q_addr = q_addr;
8721 sg_list_qp = next_qp;
8722 for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
8723 sg_list_qp = AscReadLramByte(iop_base,
8724 (ushort)(sg_q_addr
8725 + (ushort)
8726 ASC_SCSIQ_B_FWD));
8727 sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
8728 if (sg_list_qp == ASC_QLINK_END) {
8729 AscSetLibErrorCode(asc_dvc,
8730 ASCQ_ERR_SG_Q_LINKS);
8731 scsiq->d3.done_stat = QD_WITH_ERROR;
8732 scsiq->d3.host_stat =
8733 QHSTA_D_QDONE_SG_LIST_CORRUPTED;
8734 goto FATAL_ERR_QDONE;
8735 }
8736 AscWriteLramByte(iop_base,
8737 (ushort)(sg_q_addr + (ushort)
8738 ASC_SCSIQ_B_STATUS),
8739 QS_FREE);
8740 }
8741 n_q_used = sg_queue_cnt + 1;
8742 AscPutVarDoneQTail(iop_base, sg_list_qp);
8743 }
8744 if (asc_dvc->queue_full_or_busy & target_id) {
8745 cur_target_qng = AscReadLramByte(iop_base,
8746 (ushort)((ushort)
8747 ASC_QADR_BEG
8748 + (ushort)
8749 scsiq->d2.
8750 target_ix));
8751 if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
8752 scsi_busy = AscReadLramByte(iop_base, (ushort)
8753 ASCV_SCSIBUSY_B);
8754 scsi_busy &= ~target_id;
8755 AscWriteLramByte(iop_base,
8756 (ushort)ASCV_SCSIBUSY_B,
8757 scsi_busy);
8758 asc_dvc->queue_full_or_busy &= ~target_id;
8759 }
8760 }
8761 if (asc_dvc->cur_total_qng >= n_q_used) {
8762 asc_dvc->cur_total_qng -= n_q_used;
8763 if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
8764 asc_dvc->cur_dvc_qng[tid_no]--;
8765 }
8766 } else {
8767 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
8768 scsiq->d3.done_stat = QD_WITH_ERROR;
8769 goto FATAL_ERR_QDONE;
8770 }
8771 if ((scsiq->d2.srb_ptr == 0UL) ||
8772 ((scsiq->q_status & QS_ABORTED) != 0)) {
8773 return (0x11);
8774 } else if (scsiq->q_status == QS_DONE) {
8775 false_overrun = FALSE;
8776 if (scsiq->extra_bytes != 0) {
8777 scsiq->remain_bytes +=
8778 (ADV_DCNT)scsiq->extra_bytes;
8779 }
8780 if (scsiq->d3.done_stat == QD_WITH_ERROR) {
8781 if (scsiq->d3.host_stat ==
8782 QHSTA_M_DATA_OVER_RUN) {
8783 if ((scsiq->
8784 cntl & (QC_DATA_IN | QC_DATA_OUT))
8785 == 0) {
8786 scsiq->d3.done_stat =
8787 QD_NO_ERROR;
8788 scsiq->d3.host_stat =
8789 QHSTA_NO_ERROR;
8790 } else if (false_overrun) {
8791 scsiq->d3.done_stat =
8792 QD_NO_ERROR;
8793 scsiq->d3.host_stat =
8794 QHSTA_NO_ERROR;
8795 }
8796 } else if (scsiq->d3.host_stat ==
8797 QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
8798 AscStopChip(iop_base);
8799 AscSetChipControl(iop_base,
8800 (uchar)(CC_SCSI_RESET
8801 | CC_HALT));
8802 DvcDelayNanoSecond(asc_dvc, 60000);
8803 AscSetChipControl(iop_base, CC_HALT);
8804 AscSetChipStatus(iop_base,
8805 CIW_CLR_SCSI_RESET_INT);
8806 AscSetChipStatus(iop_base, 0);
8807 AscSetChipControl(iop_base, 0);
8808 }
8809 }
8810 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8811 (*asc_isr_callback) (asc_dvc, scsiq);
8812 } else {
8813 if ((AscReadLramByte(iop_base,
8814 (ushort)(q_addr + (ushort)
8815 ASC_SCSIQ_CDB_BEG))
8816 == START_STOP)) {
8817 asc_dvc->unit_not_ready &= ~target_id;
8818 if (scsiq->d3.done_stat != QD_NO_ERROR) {
8819 asc_dvc->start_motor &=
8820 ~target_id;
8821 }
8822 }
8823 }
8824 return (1);
8825 } else {
8826 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
8827 FATAL_ERR_QDONE:
8828 if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
8829 (*asc_isr_callback) (asc_dvc, scsiq);
8830 }
8831 return (0x80);
8832 }
8833 }
8834 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008835}
8836
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008837static int AscISR(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008838{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008839 ASC_CS_TYPE chipstat;
8840 PortAddr iop_base;
8841 ushort saved_ram_addr;
8842 uchar ctrl_reg;
8843 uchar saved_ctrl_reg;
8844 int int_pending;
8845 int status;
8846 uchar host_flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008847
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008848 iop_base = asc_dvc->iop_base;
8849 int_pending = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07008850
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008851 if (AscIsIntPending(iop_base) == 0) {
8852 return int_pending;
8853 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07008854
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008855 if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
8856 || (asc_dvc->isr_callback == 0)
8857 ) {
8858 return (ERR);
8859 }
8860 if (asc_dvc->in_critical_cnt != 0) {
8861 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
8862 return (ERR);
8863 }
8864 if (asc_dvc->is_in_int) {
8865 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
8866 return (ERR);
8867 }
8868 asc_dvc->is_in_int = TRUE;
8869 ctrl_reg = AscGetChipControl(iop_base);
8870 saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
8871 CC_SINGLE_STEP | CC_DIAG | CC_TEST));
8872 chipstat = AscGetChipStatus(iop_base);
8873 if (chipstat & CSW_SCSI_RESET_LATCH) {
8874 if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
8875 int i = 10;
8876 int_pending = TRUE;
8877 asc_dvc->sdtr_done = 0;
8878 saved_ctrl_reg &= (uchar)(~CC_HALT);
8879 while ((AscGetChipStatus(iop_base) &
8880 CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
8881 DvcSleepMilliSecond(100);
8882 }
8883 AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
8884 AscSetChipControl(iop_base, CC_HALT);
8885 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
8886 AscSetChipStatus(iop_base, 0);
8887 chipstat = AscGetChipStatus(iop_base);
8888 }
8889 }
8890 saved_ram_addr = AscGetChipLramAddr(iop_base);
8891 host_flag = AscReadLramByte(iop_base,
8892 ASCV_HOST_FLAG_B) &
8893 (uchar)(~ASC_HOST_FLAG_IN_ISR);
8894 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
8895 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
8896 if ((chipstat & CSW_INT_PENDING)
8897 || (int_pending)
8898 ) {
8899 AscAckInterrupt(iop_base);
8900 int_pending = TRUE;
8901 if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
8902 if (AscIsrChipHalted(asc_dvc) == ERR) {
8903 goto ISR_REPORT_QDONE_FATAL_ERROR;
8904 } else {
8905 saved_ctrl_reg &= (uchar)(~CC_HALT);
8906 }
8907 } else {
8908 ISR_REPORT_QDONE_FATAL_ERROR:
8909 if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
8910 while (((status =
8911 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
8912 }
8913 } else {
8914 do {
8915 if ((status =
8916 AscIsrQDone(asc_dvc)) == 1) {
8917 break;
8918 }
8919 } while (status == 0x11);
8920 }
8921 if ((status & 0x80) != 0)
8922 int_pending = ERR;
8923 }
8924 }
8925 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
8926 AscSetChipLramAddr(iop_base, saved_ram_addr);
8927 AscSetChipControl(iop_base, saved_ctrl_reg);
8928 asc_dvc->is_in_int = FALSE;
8929 return (int_pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07008930}
8931
8932/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04008933static uchar _asc_mcode_buf[] = {
8934 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8935 0x00, 0x00, 0x00, 0x00,
8936 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
8937 0x00, 0x00, 0x00, 0x00,
8938 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8939 0x00, 0x00, 0x00, 0x00,
8940 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8941 0x00, 0x00, 0x00, 0x00,
8942 0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
8943 0x00, 0xFF, 0x00, 0x00,
8944 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
8945 0x00, 0x00, 0x00, 0x00,
8946 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
8947 0x00, 0x00, 0x00, 0x00,
8948 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
8949 0x00, 0x00, 0x00, 0x00,
8950 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
8951 0x03, 0x23, 0x36, 0x40,
8952 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
8953 0xC2, 0x00, 0x92, 0x80,
8954 0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
8955 0xB6, 0x00, 0x92, 0x80,
8956 0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
8957 0x92, 0x80, 0x80, 0x62,
8958 0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
8959 0xCD, 0x04, 0x4D, 0x00,
8960 0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
8961 0xE6, 0x84, 0xD2, 0xC1,
8962 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
8963 0xC6, 0x81, 0xC2, 0x88,
8964 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
8965 0x84, 0x97, 0x07, 0xA6,
8966 0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
8967 0xC2, 0x88, 0xCE, 0x00,
8968 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
8969 0x80, 0x63, 0x07, 0xA6,
8970 0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
8971 0x34, 0x01, 0x00, 0x33,
8972 0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
8973 0x68, 0x98, 0x4D, 0x04,
8974 0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
8975 0xF8, 0x88, 0xFB, 0x23,
8976 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
8977 0x00, 0x33, 0x0A, 0x00,
8978 0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
8979 0xC2, 0x88, 0xCD, 0x04,
8980 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
8981 0x06, 0xAB, 0x82, 0x01,
8982 0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
8983 0x3C, 0x01, 0x00, 0x05,
8984 0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
8985 0x15, 0x23, 0xA1, 0x01,
8986 0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
8987 0x06, 0x61, 0x00, 0xA0,
8988 0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
8989 0xC2, 0x88, 0x06, 0x23,
8990 0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
8991 0x57, 0x60, 0x00, 0xA0,
8992 0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
8993 0x4B, 0x00, 0x06, 0x61,
8994 0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
8995 0x4F, 0x00, 0x84, 0x97,
8996 0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
8997 0x48, 0x04, 0x84, 0x80,
8998 0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
8999 0x81, 0x73, 0x06, 0x29,
9000 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
9001 0x04, 0x98, 0xF0, 0x80,
9002 0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
9003 0x34, 0x02, 0x03, 0xA6,
9004 0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
9005 0x46, 0x82, 0xFE, 0x95,
9006 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
9007 0x07, 0xA6, 0x5A, 0x02,
9008 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
9009 0x48, 0x82, 0x60, 0x96,
9010 0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
9011 0x04, 0x01, 0x0C, 0xDC,
9012 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
9013 0x6F, 0x00, 0xA5, 0x01,
9014 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
9015 0x02, 0xA6, 0xAA, 0x02,
9016 0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
9017 0x01, 0xA6, 0xB4, 0x02,
9018 0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
9019 0x80, 0x63, 0x00, 0x43,
9020 0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
9021 0x04, 0x61, 0x84, 0x01,
9022 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
9023 0x00, 0x00, 0xEA, 0x82,
9024 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
9025 0x00, 0x33, 0x1F, 0x00,
9026 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
9027 0xB6, 0x2D, 0x01, 0xA6,
9028 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
9029 0x10, 0x03, 0x03, 0xA6,
9030 0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
9031 0x7C, 0x95, 0xEE, 0x82,
9032 0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
9033 0x04, 0x01, 0x2D, 0xC8,
9034 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
9035 0x05, 0x05, 0x86, 0x98,
9036 0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
9037 0x3C, 0x04, 0x06, 0xA6,
9038 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
9039 0x7C, 0x95, 0x32, 0x83,
9040 0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
9041 0xEB, 0x04, 0x00, 0x33,
9042 0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
9043 0xFF, 0xA2, 0x7A, 0x03,
9044 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
9045 0x00, 0xA2, 0x9A, 0x03,
9046 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
9047 0x01, 0xA6, 0x96, 0x03,
9048 0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
9049 0xA4, 0x03, 0x00, 0xA6,
9050 0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
9051 0x07, 0xA6, 0xB2, 0x03,
9052 0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
9053 0xA8, 0x98, 0x80, 0x42,
9054 0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
9055 0xC0, 0x83, 0x00, 0x33,
9056 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
9057 0xA0, 0x01, 0x12, 0x23,
9058 0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
9059 0x80, 0x67, 0x05, 0x23,
9060 0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
9061 0x06, 0xA6, 0x0A, 0x04,
9062 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
9063 0xF4, 0x83, 0x20, 0x84,
9064 0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
9065 0x83, 0x03, 0x80, 0x63,
9066 0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
9067 0x38, 0x04, 0x00, 0x33,
9068 0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
9069 0x1D, 0x01, 0x06, 0xCC,
9070 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
9071 0xA2, 0x0D, 0x80, 0x63,
9072 0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
9073 0x80, 0x63, 0xA3, 0x01,
9074 0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
9075 0x76, 0x04, 0xE0, 0x00,
9076 0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
9077 0x00, 0x33, 0x1E, 0x00,
9078 0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
9079 0x08, 0x23, 0x22, 0xA3,
9080 0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
9081 0xC4, 0x04, 0x42, 0x23,
9082 0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
9083 0xF8, 0x88, 0x04, 0x98,
9084 0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
9085 0x81, 0x62, 0xE8, 0x81,
9086 0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
9087 0x00, 0x33, 0x00, 0x81,
9088 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
9089 0xF8, 0x88, 0x04, 0x23,
9090 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
9091 0xF4, 0x04, 0x00, 0x33,
9092 0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
9093 0x04, 0x23, 0xA0, 0x01,
9094 0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
9095 0x00, 0xA3, 0x22, 0x05,
9096 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
9097 0x46, 0x97, 0xCD, 0x04,
9098 0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
9099 0x82, 0x01, 0x34, 0x85,
9100 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
9101 0x1D, 0x01, 0x04, 0xD6,
9102 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
9103 0x49, 0x00, 0x81, 0x01,
9104 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
9105 0x49, 0x04, 0x80, 0x01,
9106 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
9107 0x01, 0x23, 0xEA, 0x00,
9108 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
9109 0x07, 0xA4, 0xF8, 0x05,
9110 0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
9111 0xC2, 0x88, 0x04, 0xA0,
9112 0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
9113 0x00, 0xA2, 0xA4, 0x05,
9114 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
9115 0x62, 0x97, 0x04, 0x85,
9116 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
9117 0xF4, 0x85, 0x03, 0xA0,
9118 0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
9119 0xCC, 0x86, 0x07, 0xA0,
9120 0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
9121 0x80, 0x67, 0x80, 0x63,
9122 0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
9123 0xF8, 0x88, 0x07, 0x23,
9124 0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
9125 0x00, 0x63, 0x4A, 0x00,
9126 0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
9127 0x07, 0x41, 0x83, 0x03,
9128 0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
9129 0x1D, 0x01, 0x01, 0xD6,
9130 0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
9131 0x07, 0xA6, 0x7C, 0x05,
9132 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
9133 0x52, 0x00, 0x06, 0x61,
9134 0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
9135 0x00, 0x63, 0x1D, 0x01,
9136 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
9137 0x07, 0x41, 0x00, 0x63,
9138 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
9139 0xDF, 0x00, 0x06, 0xA6,
9140 0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
9141 0x00, 0x40, 0xC0, 0x20,
9142 0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
9143 0x06, 0xA6, 0x94, 0x06,
9144 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
9145 0x40, 0x0E, 0x80, 0x63,
9146 0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
9147 0x80, 0x63, 0x00, 0x43,
9148 0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
9149 0x80, 0x67, 0x40, 0x0E,
9150 0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
9151 0x07, 0xA6, 0xD6, 0x06,
9152 0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
9153 0x0A, 0x2B, 0x07, 0xA6,
9154 0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
9155 0xF4, 0x06, 0xC0, 0x0E,
9156 0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
9157 0x81, 0x62, 0x04, 0x01,
9158 0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
9159 0x8C, 0x06, 0x00, 0x33,
9160 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
9161 0x80, 0x63, 0x06, 0xA6,
9162 0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
9163 0x00, 0x00, 0x80, 0x67,
9164 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
9165 0xBF, 0x23, 0x04, 0x61,
9166 0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
9167 0x00, 0x01, 0xF2, 0x00,
9168 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
9169 0x80, 0x05, 0x81, 0x05,
9170 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
9171 0x70, 0x00, 0x81, 0x01,
9172 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
9173 0x70, 0x00, 0x80, 0x01,
9174 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
9175 0xF1, 0x00, 0x70, 0x00,
9176 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
9177 0x71, 0x04, 0x70, 0x00,
9178 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
9179 0xA3, 0x01, 0xA2, 0x01,
9180 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
9181 0xC4, 0x07, 0x00, 0x33,
9182 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
9183 0x48, 0x00, 0xB0, 0x01,
9184 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
9185 0x00, 0xA2, 0xE4, 0x07,
9186 0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
9187 0x05, 0x05, 0x00, 0x63,
9188 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
9189 0x76, 0x08, 0x80, 0x02,
9190 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
9191 0x00, 0x02, 0x00, 0xA0,
9192 0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
9193 0x00, 0x63, 0xF3, 0x04,
9194 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
9195 0x00, 0xA2, 0x44, 0x08,
9196 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
9197 0x24, 0x08, 0x04, 0x98,
9198 0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
9199 0x5A, 0x88, 0x02, 0x01,
9200 0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
9201 0x00, 0xA3, 0x64, 0x08,
9202 0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
9203 0x06, 0xA6, 0x76, 0x08,
9204 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
9205 0x00, 0x63, 0x38, 0x2B,
9206 0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
9207 0x05, 0x05, 0xB2, 0x09,
9208 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
9209 0x80, 0x32, 0x80, 0x36,
9210 0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
9211 0x40, 0x36, 0x40, 0x3A,
9212 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
9213 0x5D, 0x00, 0xFE, 0xC3,
9214 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
9215 0xFF, 0xFD, 0x80, 0x73,
9216 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
9217 0xA1, 0x23, 0xA1, 0x01,
9218 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
9219 0x80, 0x00, 0x03, 0xC2,
9220 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
9221 0xA0, 0x01, 0xE6, 0x84,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009222};
9223
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009224static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
9225static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009226
9227#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009228static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
9229 INQUIRY,
9230 REQUEST_SENSE,
9231 READ_CAPACITY,
9232 READ_TOC,
9233 MODE_SELECT,
9234 MODE_SENSE,
9235 MODE_SELECT_10,
9236 MODE_SENSE_10,
9237 0xFF,
9238 0xFF,
9239 0xFF,
9240 0xFF,
9241 0xFF,
9242 0xFF,
9243 0xFF,
9244 0xFF
Linus Torvalds1da177e2005-04-16 15:20:36 -07009245};
9246
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009247static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009248{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009249 PortAddr iop_base;
9250 ulong last_int_level;
9251 int sta;
9252 int n_q_required;
9253 int disable_syn_offset_one_fix;
9254 int i;
9255 ASC_PADDR addr;
9256 ASC_EXE_CALLBACK asc_exe_callback;
9257 ushort sg_entry_cnt = 0;
9258 ushort sg_entry_cnt_minus_one = 0;
9259 uchar target_ix;
9260 uchar tid_no;
9261 uchar sdtr_data;
9262 uchar extra_bytes;
9263 uchar scsi_cmd;
9264 uchar disable_cmd;
9265 ASC_SG_HEAD *sg_head;
9266 ASC_DCNT data_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009267
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009268 iop_base = asc_dvc->iop_base;
9269 sg_head = scsiq->sg_head;
9270 asc_exe_callback = asc_dvc->exe_callback;
9271 if (asc_dvc->err_code != 0)
9272 return (ERR);
9273 if (scsiq == (ASC_SCSI_Q *)0L) {
9274 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
9275 return (ERR);
9276 }
9277 scsiq->q1.q_no = 0;
9278 if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
9279 scsiq->q1.extra_bytes = 0;
9280 }
9281 sta = 0;
9282 target_ix = scsiq->q2.target_ix;
9283 tid_no = ASC_TIX_TO_TID(target_ix);
9284 n_q_required = 1;
9285 if (scsiq->cdbptr[0] == REQUEST_SENSE) {
9286 if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
9287 asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
9288 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9289 AscMsgOutSDTR(asc_dvc,
9290 asc_dvc->
9291 sdtr_period_tbl[(sdtr_data >> 4) &
9292 (uchar)(asc_dvc->
9293 max_sdtr_index -
9294 1)],
9295 (uchar)(sdtr_data & (uchar)
9296 ASC_SYN_MAX_OFFSET));
9297 scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
9298 }
9299 }
9300 last_int_level = DvcEnterCritical();
9301 if (asc_dvc->in_critical_cnt != 0) {
9302 DvcLeaveCritical(last_int_level);
9303 AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
9304 return (ERR);
9305 }
9306 asc_dvc->in_critical_cnt++;
9307 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9308 if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
9309 asc_dvc->in_critical_cnt--;
9310 DvcLeaveCritical(last_int_level);
9311 return (ERR);
9312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009313#if !CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009314 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9315 asc_dvc->in_critical_cnt--;
9316 DvcLeaveCritical(last_int_level);
9317 return (ERR);
9318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009319#endif /* !CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009320 if (sg_entry_cnt == 1) {
9321 scsiq->q1.data_addr =
9322 (ADV_PADDR)sg_head->sg_list[0].addr;
9323 scsiq->q1.data_cnt =
9324 (ADV_DCNT)sg_head->sg_list[0].bytes;
9325 scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
9326 }
9327 sg_entry_cnt_minus_one = sg_entry_cnt - 1;
9328 }
9329 scsi_cmd = scsiq->cdbptr[0];
9330 disable_syn_offset_one_fix = FALSE;
9331 if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
9332 !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
9333 if (scsiq->q1.cntl & QC_SG_HEAD) {
9334 data_cnt = 0;
9335 for (i = 0; i < sg_entry_cnt; i++) {
9336 data_cnt +=
9337 (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
9338 bytes);
9339 }
9340 } else {
9341 data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
9342 }
9343 if (data_cnt != 0UL) {
9344 if (data_cnt < 512UL) {
9345 disable_syn_offset_one_fix = TRUE;
9346 } else {
9347 for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
9348 i++) {
9349 disable_cmd =
9350 _syn_offset_one_disable_cmd[i];
9351 if (disable_cmd == 0xFF) {
9352 break;
9353 }
9354 if (scsi_cmd == disable_cmd) {
9355 disable_syn_offset_one_fix =
9356 TRUE;
9357 break;
9358 }
9359 }
9360 }
9361 }
9362 }
9363 if (disable_syn_offset_one_fix) {
9364 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9365 scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
9366 ASC_TAG_FLAG_DISABLE_DISCONNECT);
9367 } else {
9368 scsiq->q2.tag_code &= 0x27;
9369 }
9370 if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
9371 if (asc_dvc->bug_fix_cntl) {
9372 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9373 if ((scsi_cmd == READ_6) ||
9374 (scsi_cmd == READ_10)) {
9375 addr =
9376 (ADV_PADDR)le32_to_cpu(sg_head->
9377 sg_list
9378 [sg_entry_cnt_minus_one].
9379 addr) +
9380 (ADV_DCNT)le32_to_cpu(sg_head->
9381 sg_list
9382 [sg_entry_cnt_minus_one].
9383 bytes);
9384 extra_bytes =
9385 (uchar)((ushort)addr & 0x0003);
9386 if ((extra_bytes != 0)
9387 &&
9388 ((scsiq->q2.
9389 tag_code &
9390 ASC_TAG_FLAG_EXTRA_BYTES)
9391 == 0)) {
9392 scsiq->q2.tag_code |=
9393 ASC_TAG_FLAG_EXTRA_BYTES;
9394 scsiq->q1.extra_bytes =
9395 extra_bytes;
9396 data_cnt =
9397 le32_to_cpu(sg_head->
9398 sg_list
9399 [sg_entry_cnt_minus_one].
9400 bytes);
9401 data_cnt -=
9402 (ASC_DCNT) extra_bytes;
9403 sg_head->
9404 sg_list
9405 [sg_entry_cnt_minus_one].
9406 bytes =
9407 cpu_to_le32(data_cnt);
9408 }
9409 }
9410 }
9411 }
9412 sg_head->entry_to_copy = sg_head->entry_cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009413#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009414 /*
9415 * Set the sg_entry_cnt to the maximum possible. The rest of
9416 * the SG elements will be copied when the RISC completes the
9417 * SG elements that fit and halts.
9418 */
9419 if (sg_entry_cnt > ASC_MAX_SG_LIST) {
9420 sg_entry_cnt = ASC_MAX_SG_LIST;
9421 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009422#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009423 n_q_required = AscSgListToQueue(sg_entry_cnt);
9424 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
9425 (uint) n_q_required)
9426 || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9427 if ((sta =
9428 AscSendScsiQueue(asc_dvc, scsiq,
9429 n_q_required)) == 1) {
9430 asc_dvc->in_critical_cnt--;
9431 if (asc_exe_callback != 0) {
9432 (*asc_exe_callback) (asc_dvc, scsiq);
9433 }
9434 DvcLeaveCritical(last_int_level);
9435 return (sta);
9436 }
9437 }
9438 } else {
9439 if (asc_dvc->bug_fix_cntl) {
9440 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
9441 if ((scsi_cmd == READ_6) ||
9442 (scsi_cmd == READ_10)) {
9443 addr =
9444 le32_to_cpu(scsiq->q1.data_addr) +
9445 le32_to_cpu(scsiq->q1.data_cnt);
9446 extra_bytes =
9447 (uchar)((ushort)addr & 0x0003);
9448 if ((extra_bytes != 0)
9449 &&
9450 ((scsiq->q2.
9451 tag_code &
9452 ASC_TAG_FLAG_EXTRA_BYTES)
9453 == 0)) {
9454 data_cnt =
9455 le32_to_cpu(scsiq->q1.
9456 data_cnt);
9457 if (((ushort)data_cnt & 0x01FF)
9458 == 0) {
9459 scsiq->q2.tag_code |=
9460 ASC_TAG_FLAG_EXTRA_BYTES;
9461 data_cnt -= (ASC_DCNT)
9462 extra_bytes;
9463 scsiq->q1.data_cnt =
9464 cpu_to_le32
9465 (data_cnt);
9466 scsiq->q1.extra_bytes =
9467 extra_bytes;
9468 }
9469 }
9470 }
9471 }
9472 }
9473 n_q_required = 1;
9474 if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
9475 ((scsiq->q1.cntl & QC_URGENT) != 0)) {
9476 if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
9477 n_q_required)) == 1) {
9478 asc_dvc->in_critical_cnt--;
9479 if (asc_exe_callback != 0) {
9480 (*asc_exe_callback) (asc_dvc, scsiq);
9481 }
9482 DvcLeaveCritical(last_int_level);
9483 return (sta);
9484 }
9485 }
9486 }
9487 asc_dvc->in_critical_cnt--;
9488 DvcLeaveCritical(last_int_level);
9489 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009490}
9491
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009492static int
9493AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009494{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009495 PortAddr iop_base;
9496 uchar free_q_head;
9497 uchar next_qp;
9498 uchar tid_no;
9499 uchar target_ix;
9500 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009501
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009502 iop_base = asc_dvc->iop_base;
9503 target_ix = scsiq->q2.target_ix;
9504 tid_no = ASC_TIX_TO_TID(target_ix);
9505 sta = 0;
9506 free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
9507 if (n_q_required > 1) {
9508 if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
9509 free_q_head, (uchar)
9510 (n_q_required)))
9511 != (uchar)ASC_QLINK_END) {
9512 asc_dvc->last_q_shortage = 0;
9513 scsiq->sg_head->queue_cnt = n_q_required - 1;
9514 scsiq->q1.q_no = free_q_head;
9515 if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
9516 free_q_head)) == 1) {
9517 AscPutVarFreeQHead(iop_base, next_qp);
9518 asc_dvc->cur_total_qng += (uchar)(n_q_required);
9519 asc_dvc->cur_dvc_qng[tid_no]++;
9520 }
9521 return (sta);
9522 }
9523 } else if (n_q_required == 1) {
9524 if ((next_qp = AscAllocFreeQueue(iop_base,
9525 free_q_head)) !=
9526 ASC_QLINK_END) {
9527 scsiq->q1.q_no = free_q_head;
9528 if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
9529 free_q_head)) == 1) {
9530 AscPutVarFreeQHead(iop_base, next_qp);
9531 asc_dvc->cur_total_qng++;
9532 asc_dvc->cur_dvc_qng[tid_no]++;
9533 }
9534 return (sta);
9535 }
9536 }
9537 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009538}
9539
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009540static int AscSgListToQueue(int sg_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009541{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009542 int n_sg_list_qs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009543
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009544 n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
9545 if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
9546 n_sg_list_qs++;
9547 return (n_sg_list_qs + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009548}
9549
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009550static uint
9551AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009552{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009553 uint cur_used_qs;
9554 uint cur_free_qs;
9555 ASC_SCSI_BIT_ID_TYPE target_id;
9556 uchar tid_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009557
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009558 target_id = ASC_TIX_TO_TARGET_ID(target_ix);
9559 tid_no = ASC_TIX_TO_TID(target_ix);
9560 if ((asc_dvc->unit_not_ready & target_id) ||
9561 (asc_dvc->queue_full_or_busy & target_id)) {
9562 return (0);
9563 }
9564 if (n_qs == 1) {
9565 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9566 (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
9567 } else {
9568 cur_used_qs = (uint) asc_dvc->cur_total_qng +
9569 (uint) ASC_MIN_FREE_Q;
9570 }
9571 if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
9572 cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
9573 if (asc_dvc->cur_dvc_qng[tid_no] >=
9574 asc_dvc->max_dvc_qng[tid_no]) {
9575 return (0);
9576 }
9577 return (cur_free_qs);
9578 }
9579 if (n_qs > 1) {
9580 if ((n_qs > asc_dvc->last_q_shortage)
9581 && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
9582 asc_dvc->last_q_shortage = n_qs;
9583 }
9584 }
9585 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009586}
9587
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009588static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009589{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009590 ushort q_addr;
9591 uchar tid_no;
9592 uchar sdtr_data;
9593 uchar syn_period_ix;
9594 uchar syn_offset;
9595 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009596
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009597 iop_base = asc_dvc->iop_base;
9598 if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
9599 ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
9600 tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
9601 sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
9602 syn_period_ix =
9603 (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
9604 syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
9605 AscMsgOutSDTR(asc_dvc,
9606 asc_dvc->sdtr_period_tbl[syn_period_ix],
9607 syn_offset);
9608 scsiq->q1.cntl |= QC_MSG_OUT;
9609 }
9610 q_addr = ASC_QNO_TO_QADDR(q_no);
9611 if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
9612 scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
9613 }
9614 scsiq->q1.status = QS_FREE;
9615 AscMemWordCopyPtrToLram(iop_base,
9616 q_addr + ASC_SCSIQ_CDB_BEG,
9617 (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009618
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009619 DvcPutScsiQ(iop_base,
9620 q_addr + ASC_SCSIQ_CPY_BEG,
9621 (uchar *)&scsiq->q1.cntl,
9622 ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
9623 AscWriteLramWord(iop_base,
9624 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
9625 (ushort)(((ushort)scsiq->q1.
9626 q_no << 8) | (ushort)QS_READY));
9627 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009628}
9629
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009630static int
9631AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009632{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009633 int sta;
9634 int i;
9635 ASC_SG_HEAD *sg_head;
9636 ASC_SG_LIST_Q scsi_sg_q;
9637 ASC_DCNT saved_data_addr;
9638 ASC_DCNT saved_data_cnt;
9639 PortAddr iop_base;
9640 ushort sg_list_dwords;
9641 ushort sg_index;
9642 ushort sg_entry_cnt;
9643 ushort q_addr;
9644 uchar next_qp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009645
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009646 iop_base = asc_dvc->iop_base;
9647 sg_head = scsiq->sg_head;
9648 saved_data_addr = scsiq->q1.data_addr;
9649 saved_data_cnt = scsiq->q1.data_cnt;
9650 scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
9651 scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009652#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009653 /*
9654 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
9655 * then not all SG elements will fit in the allocated queues.
9656 * The rest of the SG elements will be copied when the RISC
9657 * completes the SG elements that fit and halts.
9658 */
9659 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9660 /*
9661 * Set sg_entry_cnt to be the number of SG elements that
9662 * will fit in the allocated SG queues. It is minus 1, because
9663 * the first SG element is handled above. ASC_MAX_SG_LIST is
9664 * already inflated by 1 to account for this. For example it
9665 * may be 50 which is 1 + 7 queues * 7 SG elements.
9666 */
9667 sg_entry_cnt = ASC_MAX_SG_LIST - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009668
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009669 /*
9670 * Keep track of remaining number of SG elements that will
9671 * need to be handled from a_isr.c.
9672 */
9673 scsiq->remain_sg_entry_cnt =
9674 sg_head->entry_cnt - ASC_MAX_SG_LIST;
9675 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009676#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009677 /*
9678 * Set sg_entry_cnt to be the number of SG elements that
9679 * will fit in the allocated SG queues. It is minus 1, because
9680 * the first SG element is handled above.
9681 */
9682 sg_entry_cnt = sg_head->entry_cnt - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009683#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009685#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009686 if (sg_entry_cnt != 0) {
9687 scsiq->q1.cntl |= QC_SG_HEAD;
9688 q_addr = ASC_QNO_TO_QADDR(q_no);
9689 sg_index = 1;
9690 scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
9691 scsi_sg_q.sg_head_qp = q_no;
9692 scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
9693 for (i = 0; i < sg_head->queue_cnt; i++) {
9694 scsi_sg_q.seq_no = i + 1;
9695 if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
9696 sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
9697 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
9698 if (i == 0) {
9699 scsi_sg_q.sg_list_cnt =
9700 ASC_SG_LIST_PER_Q;
9701 scsi_sg_q.sg_cur_list_cnt =
9702 ASC_SG_LIST_PER_Q;
9703 } else {
9704 scsi_sg_q.sg_list_cnt =
9705 ASC_SG_LIST_PER_Q - 1;
9706 scsi_sg_q.sg_cur_list_cnt =
9707 ASC_SG_LIST_PER_Q - 1;
9708 }
9709 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009710#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009711 /*
9712 * This is the last SG queue in the list of
9713 * allocated SG queues. If there are more
9714 * SG elements than will fit in the allocated
9715 * queues, then set the QCSG_SG_XFER_MORE flag.
9716 */
9717 if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
9718 scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
9719 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009720#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009721 scsi_sg_q.cntl |= QCSG_SG_XFER_END;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009722#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009724#endif /* CC_VERY_LONG_SG_LIST */
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009725 sg_list_dwords = sg_entry_cnt << 1;
9726 if (i == 0) {
9727 scsi_sg_q.sg_list_cnt = sg_entry_cnt;
9728 scsi_sg_q.sg_cur_list_cnt =
9729 sg_entry_cnt;
9730 } else {
9731 scsi_sg_q.sg_list_cnt =
9732 sg_entry_cnt - 1;
9733 scsi_sg_q.sg_cur_list_cnt =
9734 sg_entry_cnt - 1;
9735 }
9736 sg_entry_cnt = 0;
9737 }
9738 next_qp = AscReadLramByte(iop_base,
9739 (ushort)(q_addr +
9740 ASC_SCSIQ_B_FWD));
9741 scsi_sg_q.q_no = next_qp;
9742 q_addr = ASC_QNO_TO_QADDR(next_qp);
9743 AscMemWordCopyPtrToLram(iop_base,
9744 q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
9745 (uchar *)&scsi_sg_q,
9746 sizeof(ASC_SG_LIST_Q) >> 1);
9747 AscMemDWordCopyPtrToLram(iop_base,
9748 q_addr + ASC_SGQ_LIST_BEG,
9749 (uchar *)&sg_head->
9750 sg_list[sg_index],
9751 sg_list_dwords);
9752 sg_index += ASC_SG_LIST_PER_Q;
9753 scsiq->next_sg_index = sg_index;
9754 }
9755 } else {
9756 scsiq->q1.cntl &= ~QC_SG_HEAD;
9757 }
9758 sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
9759 scsiq->q1.data_addr = saved_data_addr;
9760 scsiq->q1.data_cnt = saved_data_cnt;
9761 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009762}
9763
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009764static int
9765AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009766{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009767 int sta = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009768
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009769 if (AscHostReqRiscHalt(iop_base)) {
9770 sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9771 AscStartChip(iop_base);
9772 return (sta);
9773 }
9774 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009775}
9776
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009777static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009778{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009779 ASC_SCSI_BIT_ID_TYPE org_id;
9780 int i;
9781 int sta = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009782
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009783 AscSetBank(iop_base, 1);
9784 org_id = AscReadChipDvcID(iop_base);
9785 for (i = 0; i <= ASC_MAX_TID; i++) {
9786 if (org_id == (0x01 << i))
9787 break;
9788 }
9789 org_id = (ASC_SCSI_BIT_ID_TYPE) i;
9790 AscWriteChipDvcID(iop_base, id);
9791 if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
9792 AscSetBank(iop_base, 0);
9793 AscSetChipSyn(iop_base, sdtr_data);
9794 if (AscGetChipSyn(iop_base) != sdtr_data) {
9795 sta = FALSE;
9796 }
9797 } else {
9798 sta = FALSE;
9799 }
9800 AscSetBank(iop_base, 1);
9801 AscWriteChipDvcID(iop_base, org_id);
9802 AscSetBank(iop_base, 0);
9803 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009804}
9805
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009806static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009807{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009808 uchar i;
9809 ushort s_addr;
9810 PortAddr iop_base;
9811 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009812
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009813 iop_base = asc_dvc->iop_base;
9814 warn_code = 0;
9815 AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
9816 (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
9817 64) >> 1)
9818 );
9819 i = ASC_MIN_ACTIVE_QNO;
9820 s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
9821 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9822 (uchar)(i + 1));
9823 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9824 (uchar)(asc_dvc->max_total_qng));
9825 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9826 (uchar)i);
9827 i++;
9828 s_addr += ASC_QBLK_SIZE;
9829 for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
9830 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9831 (uchar)(i + 1));
9832 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9833 (uchar)(i - 1));
9834 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9835 (uchar)i);
9836 }
9837 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
9838 (uchar)ASC_QLINK_END);
9839 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
9840 (uchar)(asc_dvc->max_total_qng - 1));
9841 AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
9842 (uchar)asc_dvc->max_total_qng);
9843 i++;
9844 s_addr += ASC_QBLK_SIZE;
9845 for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
9846 i++, s_addr += ASC_QBLK_SIZE) {
9847 AscWriteLramByte(iop_base,
9848 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
9849 AscWriteLramByte(iop_base,
9850 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
9851 AscWriteLramByte(iop_base,
9852 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
9853 }
9854 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009855}
9856
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009857static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009858{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009859 PortAddr iop_base;
9860 int i;
9861 ushort lram_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009862
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009863 iop_base = asc_dvc->iop_base;
9864 AscPutRiscVarFreeQHead(iop_base, 1);
9865 AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9866 AscPutVarFreeQHead(iop_base, 1);
9867 AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
9868 AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
9869 (uchar)((int)asc_dvc->max_total_qng + 1));
9870 AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
9871 (uchar)((int)asc_dvc->max_total_qng + 2));
9872 AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
9873 asc_dvc->max_total_qng);
9874 AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
9875 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
9876 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
9877 AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
9878 AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
9879 AscPutQDoneInProgress(iop_base, 0);
9880 lram_addr = ASC_QADR_BEG;
9881 for (i = 0; i < 32; i++, lram_addr += 2) {
9882 AscWriteLramWord(iop_base, lram_addr, 0);
9883 }
9884 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009885}
9886
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009887static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009888{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009889 if (asc_dvc->err_code == 0) {
9890 asc_dvc->err_code = err_code;
9891 AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
9892 err_code);
9893 }
9894 return (err_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009895}
9896
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009897static uchar
9898AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009899{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009900 EXT_MSG sdtr_buf;
9901 uchar sdtr_period_index;
9902 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009903
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009904 iop_base = asc_dvc->iop_base;
9905 sdtr_buf.msg_type = MS_EXTEND;
9906 sdtr_buf.msg_len = MS_SDTR_LEN;
9907 sdtr_buf.msg_req = MS_SDTR_CODE;
9908 sdtr_buf.xfer_period = sdtr_period;
9909 sdtr_offset &= ASC_SYN_MAX_OFFSET;
9910 sdtr_buf.req_ack_offset = sdtr_offset;
9911 if ((sdtr_period_index =
9912 AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
9913 asc_dvc->max_sdtr_index) {
9914 AscMemWordCopyPtrToLram(iop_base,
9915 ASCV_MSGOUT_BEG,
9916 (uchar *)&sdtr_buf,
9917 sizeof(EXT_MSG) >> 1);
9918 return ((sdtr_period_index << 4) | sdtr_offset);
9919 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009920
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009921 sdtr_buf.req_ack_offset = 0;
9922 AscMemWordCopyPtrToLram(iop_base,
9923 ASCV_MSGOUT_BEG,
9924 (uchar *)&sdtr_buf,
9925 sizeof(EXT_MSG) >> 1);
9926 return (0);
9927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009928}
9929
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009930static uchar
9931AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009932{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009933 uchar byte;
9934 uchar sdtr_period_ix;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009935
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009936 sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
9937 if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
9938 ) {
9939 return (0xFF);
9940 }
9941 byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
9942 return (byte);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009943}
9944
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009945static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009946{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009947 AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
9948 AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
9949 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009950}
9951
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009952static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009953{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009954 uchar *period_table;
9955 int max_index;
9956 int min_index;
9957 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009958
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009959 period_table = asc_dvc->sdtr_period_tbl;
9960 max_index = (int)asc_dvc->max_sdtr_index;
9961 min_index = (int)asc_dvc->host_init_sdtr_index;
9962 if ((syn_time <= period_table[max_index])) {
9963 for (i = min_index; i < (max_index - 1); i++) {
9964 if (syn_time <= period_table[i]) {
9965 return ((uchar)i);
9966 }
9967 }
9968 return ((uchar)max_index);
9969 } else {
9970 return ((uchar)(max_index + 1));
9971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07009972}
9973
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009974static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009975{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009976 ushort q_addr;
9977 uchar next_qp;
9978 uchar q_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009979
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009980 q_addr = ASC_QNO_TO_QADDR(free_q_head);
9981 q_status = (uchar)AscReadLramByte(iop_base,
9982 (ushort)(q_addr +
9983 ASC_SCSIQ_B_STATUS));
9984 next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
9985 if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
9986 return (next_qp);
9987 }
9988 return (ASC_QLINK_END);
Linus Torvalds1da177e2005-04-16 15:20:36 -07009989}
9990
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009991static uchar
9992AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
Linus Torvalds1da177e2005-04-16 15:20:36 -07009993{
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009994 uchar i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07009995
Matthew Wilcox27c868c2007-07-26 10:56:23 -04009996 for (i = 0; i < n_free_q; i++) {
9997 if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
9998 == ASC_QLINK_END) {
9999 return (ASC_QLINK_END);
10000 }
10001 }
10002 return (free_q_head);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010003}
10004
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010005static int AscHostReqRiscHalt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010006{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010007 int count = 0;
10008 int sta = 0;
10009 uchar saved_stop_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010010
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010011 if (AscIsChipHalted(iop_base))
10012 return (1);
10013 saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
10014 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10015 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
10016 do {
10017 if (AscIsChipHalted(iop_base)) {
10018 sta = 1;
10019 break;
10020 }
10021 DvcSleepMilliSecond(100);
10022 } while (count++ < 20);
10023 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
10024 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010025}
10026
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010027static int AscStopQueueExe(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010028{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010029 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010030
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010031 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
10032 AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
10033 ASC_STOP_REQ_RISC_STOP);
10034 do {
10035 if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
10036 ASC_STOP_ACK_RISC_STOP) {
10037 return (1);
10038 }
10039 DvcSleepMilliSecond(100);
10040 } while (count++ < 20);
10041 }
10042 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010043}
10044
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010045static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010046{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010047 udelay(micro_sec);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010048}
10049
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010050static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010051{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010052 udelay((nano_sec + 999) / 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010053}
10054
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010055static int AscStartChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010056{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010057 AscSetChipControl(iop_base, 0);
10058 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10059 return (0);
10060 }
10061 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010062}
10063
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010064static int AscStopChip(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010065{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010066 uchar cc_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010067
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010068 cc_val =
10069 AscGetChipControl(iop_base) &
10070 (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
10071 AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
10072 AscSetChipIH(iop_base, INS_HALT);
10073 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10074 if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
10075 return (0);
10076 }
10077 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010078}
10079
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010080static int AscIsChipHalted(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010081{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010082 if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
10083 if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
10084 return (1);
10085 }
10086 }
10087 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010088}
10089
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010090static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010091{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010092 AscSetBank(iop_base, 1);
10093 AscWriteChipIH(iop_base, ins_code);
10094 AscSetBank(iop_base, 0);
10095 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010096}
10097
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010098static void AscAckInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010099{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010100 uchar host_flag;
10101 uchar risc_flag;
10102 ushort loop;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010103
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010104 loop = 0;
10105 do {
10106 risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
10107 if (loop++ > 0x7FFF) {
10108 break;
10109 }
10110 } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
10111 host_flag =
10112 AscReadLramByte(iop_base,
10113 ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
10114 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
10115 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
10116 AscSetChipStatus(iop_base, CIW_INT_ACK);
10117 loop = 0;
10118 while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
10119 AscSetChipStatus(iop_base, CIW_INT_ACK);
10120 if (loop++ > 3) {
10121 break;
10122 }
10123 }
10124 AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
10125 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010126}
10127
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010128static void AscDisableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010129{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010130 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010131
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010132 cfg = AscGetChipCfgLsw(iop_base);
10133 AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
10134 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010135}
10136
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010137static void AscEnableInterrupt(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010138{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010139 ushort cfg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010140
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010141 cfg = AscGetChipCfgLsw(iop_base);
10142 AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
10143 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010144}
10145
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010146static void AscSetBank(PortAddr iop_base, uchar bank)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010147{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010148 uchar val;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010149
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010150 val = AscGetChipControl(iop_base) &
10151 (~
10152 (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
10153 CC_CHIP_RESET));
10154 if (bank == 1) {
10155 val |= CC_BANK_ONE;
10156 } else if (bank == 2) {
10157 val |= CC_DIAG | CC_BANK_ONE;
10158 } else {
10159 val &= ~CC_BANK_ONE;
10160 }
10161 AscSetChipControl(iop_base, val);
10162 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010163}
10164
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010165static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010166{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010167 PortAddr iop_base;
10168 int i = 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010169
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010170 iop_base = asc_dvc->iop_base;
10171 while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
10172 && (i-- > 0)) {
10173 DvcSleepMilliSecond(100);
10174 }
10175 AscStopChip(iop_base);
10176 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
10177 DvcDelayNanoSecond(asc_dvc, 60000);
10178 AscSetChipIH(iop_base, INS_RFLAG_WTM);
10179 AscSetChipIH(iop_base, INS_HALT);
10180 AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
10181 AscSetChipControl(iop_base, CC_HALT);
10182 DvcSleepMilliSecond(200);
10183 AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
10184 AscSetChipStatus(iop_base, 0);
10185 return (AscIsChipHalted(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010186}
10187
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010188static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010189{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010190 if (bus_type & ASC_IS_ISA)
10191 return (ASC_MAX_ISA_DMA_COUNT);
10192 else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
10193 return (ASC_MAX_VL_DMA_COUNT);
10194 return (ASC_MAX_PCI_DMA_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010195}
10196
10197#ifdef CONFIG_ISA
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010198static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010199{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010200 ushort channel;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010201
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010202 channel = AscGetChipCfgLsw(iop_base) & 0x0003;
10203 if (channel == 0x03)
10204 return (0);
10205 else if (channel == 0x00)
10206 return (7);
10207 return (channel + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010208}
10209
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010210static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010211{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010212 ushort cfg_lsw;
10213 uchar value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010214
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010215 if ((dma_channel >= 5) && (dma_channel <= 7)) {
10216 if (dma_channel == 7)
10217 value = 0x00;
10218 else
10219 value = dma_channel - 4;
10220 cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
10221 cfg_lsw |= value;
10222 AscSetChipCfgLsw(iop_base, cfg_lsw);
10223 return (AscGetIsaDmaChannel(iop_base));
10224 }
10225 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010226}
10227
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010228static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010229{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010230 speed_value &= 0x07;
10231 AscSetBank(iop_base, 1);
10232 AscWriteChipDmaSpeed(iop_base, speed_value);
10233 AscSetBank(iop_base, 0);
10234 return (AscGetIsaDmaSpeed(iop_base));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010235}
10236
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010237static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010238{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010239 uchar speed_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010240
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010241 AscSetBank(iop_base, 1);
10242 speed_value = AscReadChipDmaSpeed(iop_base);
10243 speed_value &= 0x07;
10244 AscSetBank(iop_base, 0);
10245 return (speed_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010246}
10247#endif /* CONFIG_ISA */
10248
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010249static ushort __devinit AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010250{
Matthew Wilcox9649af32007-07-26 21:51:47 -060010251 unsigned short warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010252
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010253 asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
Matthew Wilcox9649af32007-07-26 21:51:47 -060010254 if (asc_dvc->err_code != 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010255 return (UW_ERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010256
Matthew Wilcox9649af32007-07-26 21:51:47 -060010257 if (AscFindSignature(asc_dvc->iop_base)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010258 warn_code |= AscInitAscDvcVar(asc_dvc);
10259 warn_code |= AscInitFromEEP(asc_dvc);
10260 asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
10261 if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
10262 asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
10263 }
10264 } else {
10265 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10266 }
10267 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010268}
10269
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010270static ushort __devinit AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010271{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010272 ushort warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010273
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010274 asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
10275 if (asc_dvc->err_code != 0)
10276 return (UW_ERR);
10277 if (AscFindSignature(asc_dvc->iop_base)) {
10278 warn_code |= AscInitFromAscDvcVar(asc_dvc);
10279 asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
10280 } else {
10281 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10282 }
10283 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010284}
10285
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010286static ushort __devinit AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010287{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010288 PortAddr iop_base;
10289 ushort cfg_msw;
10290 ushort warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010291
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010292 iop_base = asc_dvc->iop_base;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010293 warn_code = 0;
10294 cfg_msw = AscGetChipCfgMsw(iop_base);
10295 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10296 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10297 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10298 AscSetChipCfgMsw(iop_base, cfg_msw);
10299 }
10300 if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
10301 asc_dvc->cfg->cmd_qng_enabled) {
10302 asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
10303 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10304 }
10305 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10306 warn_code |= ASC_WARN_AUTO_CONFIG;
10307 }
10308 if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
10309 if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
10310 != asc_dvc->irq_no) {
10311 asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
10312 }
10313 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010314#ifdef CONFIG_PCI
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010315 if (asc_dvc->bus_type & ASC_IS_PCI) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010316 struct pci_dev *pdev = to_pci_dev(asc_dvc->cfg->dev);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010317 cfg_msw &= 0xFFC0;
10318 AscSetChipCfgMsw(iop_base, cfg_msw);
10319 if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
10320 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060010321 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
10322 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010323 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
10324 asc_dvc->bug_fix_cntl |=
10325 ASC_BUG_FIX_ASYN_USE_SYN;
10326 }
10327 }
Matthew Wilcox9649af32007-07-26 21:51:47 -060010328 } else
10329#endif /* CONFIG_PCI */
10330 if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010331 if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
10332 == ASC_CHIP_VER_ASYN_BUG) {
10333 asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
10334 }
10335 }
10336 if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
10337 asc_dvc->cfg->chip_scsi_id) {
10338 asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
10339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010340#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010341 if (asc_dvc->bus_type & ASC_IS_ISA) {
10342 AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
10343 AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
10344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010345#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010346 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010347}
10348
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010349static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010350{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010351 ushort warn_code;
10352 PortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010353
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010354 iop_base = asc_dvc->iop_base;
10355 warn_code = 0;
10356 if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
10357 !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
10358 AscResetChipAndScsiBus(asc_dvc);
10359 DvcSleepMilliSecond((ASC_DCNT)
10360 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10361 }
10362 asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
10363 if (asc_dvc->err_code != 0)
10364 return (UW_ERR);
10365 if (!AscFindSignature(asc_dvc->iop_base)) {
10366 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
10367 return (warn_code);
10368 }
10369 AscDisableInterrupt(iop_base);
10370 warn_code |= AscInitLram(asc_dvc);
10371 if (asc_dvc->err_code != 0)
10372 return (UW_ERR);
10373 ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
10374 (ulong)_asc_mcode_chksum);
10375 if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
10376 _asc_mcode_size) != _asc_mcode_chksum) {
10377 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
10378 return (warn_code);
10379 }
10380 warn_code |= AscInitMicroCodeVar(asc_dvc);
10381 asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
10382 AscEnableInterrupt(iop_base);
10383 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010384}
10385
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010386static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010387{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010388 int i;
10389 PortAddr iop_base;
10390 ushort warn_code;
10391 uchar chip_version;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010392
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010393 iop_base = asc_dvc->iop_base;
10394 warn_code = 0;
10395 asc_dvc->err_code = 0;
10396 if ((asc_dvc->bus_type &
10397 (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
10398 asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
10399 }
10400 AscSetChipControl(iop_base, CC_HALT);
10401 AscSetChipStatus(iop_base, 0);
10402 asc_dvc->bug_fix_cntl = 0;
10403 asc_dvc->pci_fix_asyn_xfer = 0;
10404 asc_dvc->pci_fix_asyn_xfer_always = 0;
10405 /* asc_dvc->init_state initalized in AscInitGetConfig(). */
10406 asc_dvc->sdtr_done = 0;
10407 asc_dvc->cur_total_qng = 0;
10408 asc_dvc->is_in_int = 0;
10409 asc_dvc->in_critical_cnt = 0;
10410 asc_dvc->last_q_shortage = 0;
10411 asc_dvc->use_tagged_qng = 0;
10412 asc_dvc->no_scam = 0;
10413 asc_dvc->unit_not_ready = 0;
10414 asc_dvc->queue_full_or_busy = 0;
10415 asc_dvc->redo_scam = 0;
10416 asc_dvc->res2 = 0;
10417 asc_dvc->host_init_sdtr_index = 0;
10418 asc_dvc->cfg->can_tagged_qng = 0;
10419 asc_dvc->cfg->cmd_qng_enabled = 0;
10420 asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
10421 asc_dvc->init_sdtr = 0;
10422 asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
10423 asc_dvc->scsi_reset_wait = 3;
10424 asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
10425 asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
10426 asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
10427 asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
10428 asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
10429 asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
10430 asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
10431 ASC_LIB_VERSION_MINOR;
10432 chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
10433 asc_dvc->cfg->chip_version = chip_version;
10434 asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
10435 asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
10436 asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
10437 asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
10438 asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
10439 asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
10440 asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
10441 asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
10442 asc_dvc->max_sdtr_index = 7;
10443 if ((asc_dvc->bus_type & ASC_IS_PCI) &&
10444 (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
10445 asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
10446 asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
10447 asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
10448 asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
10449 asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
10450 asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
10451 asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
10452 asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
10453 asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
10454 asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
10455 asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
10456 asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
10457 asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
10458 asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
10459 asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
10460 asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
10461 asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
10462 asc_dvc->max_sdtr_index = 15;
10463 if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
10464 AscSetExtraControl(iop_base,
10465 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10466 } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
10467 AscSetExtraControl(iop_base,
10468 (SEC_ACTIVE_NEGATE |
10469 SEC_ENABLE_FILTER));
10470 }
10471 }
10472 if (asc_dvc->bus_type == ASC_IS_PCI) {
10473 AscSetExtraControl(iop_base,
10474 (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
10475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010476
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010477 asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
10478 if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
10479 AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
10480 asc_dvc->bus_type = ASC_IS_ISAPNP;
10481 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010482#ifdef CONFIG_ISA
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010483 if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
10484 asc_dvc->cfg->isa_dma_channel =
10485 (uchar)AscGetIsaDmaChannel(iop_base);
10486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010487#endif /* CONFIG_ISA */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010488 for (i = 0; i <= ASC_MAX_TID; i++) {
10489 asc_dvc->cur_dvc_qng[i] = 0;
10490 asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
10491 asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
10492 asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
10493 asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
10494 }
10495 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010496}
10497
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010498static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010499{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010500 ASCEEP_CONFIG eep_config_buf;
10501 ASCEEP_CONFIG *eep_config;
10502 PortAddr iop_base;
10503 ushort chksum;
10504 ushort warn_code;
10505 ushort cfg_msw, cfg_lsw;
10506 int i;
10507 int write_eep = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010508
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010509 iop_base = asc_dvc->iop_base;
10510 warn_code = 0;
10511 AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
10512 AscStopQueueExe(iop_base);
10513 if ((AscStopChip(iop_base) == FALSE) ||
10514 (AscGetChipScsiCtrl(iop_base) != 0)) {
10515 asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
10516 AscResetChipAndScsiBus(asc_dvc);
10517 DvcSleepMilliSecond((ASC_DCNT)
10518 ((ushort)asc_dvc->scsi_reset_wait * 1000));
10519 }
10520 if (AscIsChipHalted(iop_base) == FALSE) {
10521 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10522 return (warn_code);
10523 }
10524 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10525 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10526 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10527 return (warn_code);
10528 }
10529 eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
10530 cfg_msw = AscGetChipCfgMsw(iop_base);
10531 cfg_lsw = AscGetChipCfgLsw(iop_base);
10532 if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
10533 cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
10534 warn_code |= ASC_WARN_CFG_MSW_RECOVER;
10535 AscSetChipCfgMsw(iop_base, cfg_msw);
10536 }
10537 chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
10538 ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
10539 if (chksum == 0) {
10540 chksum = 0xaa55;
10541 }
10542 if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
10543 warn_code |= ASC_WARN_AUTO_CONFIG;
10544 if (asc_dvc->cfg->chip_version == 3) {
10545 if (eep_config->cfg_lsw != cfg_lsw) {
10546 warn_code |= ASC_WARN_EEPROM_RECOVER;
10547 eep_config->cfg_lsw =
10548 AscGetChipCfgLsw(iop_base);
10549 }
10550 if (eep_config->cfg_msw != cfg_msw) {
10551 warn_code |= ASC_WARN_EEPROM_RECOVER;
10552 eep_config->cfg_msw =
10553 AscGetChipCfgMsw(iop_base);
10554 }
10555 }
10556 }
10557 eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
10558 eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
10559 ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
10560 eep_config->chksum);
10561 if (chksum != eep_config->chksum) {
10562 if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
10563 ASC_CHIP_VER_PCI_ULTRA_3050) {
10564 ASC_DBG(1,
10565 "AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
10566 eep_config->init_sdtr = 0xFF;
10567 eep_config->disc_enable = 0xFF;
10568 eep_config->start_motor = 0xFF;
10569 eep_config->use_cmd_qng = 0;
10570 eep_config->max_total_qng = 0xF0;
10571 eep_config->max_tag_qng = 0x20;
10572 eep_config->cntl = 0xBFFF;
10573 ASC_EEP_SET_CHIP_ID(eep_config, 7);
10574 eep_config->no_scam = 0;
10575 eep_config->adapter_info[0] = 0;
10576 eep_config->adapter_info[1] = 0;
10577 eep_config->adapter_info[2] = 0;
10578 eep_config->adapter_info[3] = 0;
10579 eep_config->adapter_info[4] = 0;
10580 /* Indicate EEPROM-less board. */
10581 eep_config->adapter_info[5] = 0xBB;
10582 } else {
10583 ASC_PRINT
10584 ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
10585 write_eep = 1;
10586 warn_code |= ASC_WARN_EEPROM_CHKSUM;
10587 }
10588 }
10589 asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
10590 asc_dvc->cfg->disc_enable = eep_config->disc_enable;
10591 asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
10592 asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
10593 asc_dvc->start_motor = eep_config->start_motor;
10594 asc_dvc->dvc_cntl = eep_config->cntl;
10595 asc_dvc->no_scam = eep_config->no_scam;
10596 asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
10597 asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
10598 asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
10599 asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
10600 asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
10601 asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
10602 if (!AscTestExternalLram(asc_dvc)) {
10603 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
10604 ASC_IS_PCI_ULTRA)) {
10605 eep_config->max_total_qng =
10606 ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
10607 eep_config->max_tag_qng =
10608 ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
10609 } else {
10610 eep_config->cfg_msw |= 0x0800;
10611 cfg_msw |= 0x0800;
10612 AscSetChipCfgMsw(iop_base, cfg_msw);
10613 eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
10614 eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
10615 }
10616 } else {
10617 }
10618 if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
10619 eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
10620 }
10621 if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
10622 eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
10623 }
10624 if (eep_config->max_tag_qng > eep_config->max_total_qng) {
10625 eep_config->max_tag_qng = eep_config->max_total_qng;
10626 }
10627 if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
10628 eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
10629 }
10630 asc_dvc->max_total_qng = eep_config->max_total_qng;
10631 if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
10632 eep_config->use_cmd_qng) {
10633 eep_config->disc_enable = eep_config->use_cmd_qng;
10634 warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
10635 }
10636 if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
10637 asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
10638 }
10639 ASC_EEP_SET_CHIP_ID(eep_config,
10640 ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
10641 asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
10642 if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
10643 !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
10644 asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
10645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010646
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010647 for (i = 0; i <= ASC_MAX_TID; i++) {
10648 asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
10649 asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
10650 asc_dvc->cfg->sdtr_period_offset[i] =
10651 (uchar)(ASC_DEF_SDTR_OFFSET |
10652 (asc_dvc->host_init_sdtr_index << 4));
10653 }
10654 eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
10655 if (write_eep) {
10656 if ((i =
10657 AscSetEEPConfig(iop_base, eep_config,
10658 asc_dvc->bus_type)) != 0) {
10659 ASC_PRINT1
10660 ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
10661 i);
10662 } else {
10663 ASC_PRINT
10664 ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
10665 }
10666 }
10667 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010668}
10669
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010670static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010671{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010672 int i;
10673 ushort warn_code;
10674 PortAddr iop_base;
10675 ASC_PADDR phy_addr;
10676 ASC_DCNT phy_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010677
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010678 iop_base = asc_dvc->iop_base;
10679 warn_code = 0;
10680 for (i = 0; i <= ASC_MAX_TID; i++) {
10681 AscPutMCodeInitSDTRAtID(iop_base, i,
10682 asc_dvc->cfg->sdtr_period_offset[i]
10683 );
10684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010685
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010686 AscInitQLinkVar(asc_dvc);
10687 AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
10688 asc_dvc->cfg->disc_enable);
10689 AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
10690 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070010691
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010692 /* Align overrun buffer on an 8 byte boundary. */
10693 phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
10694 phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
10695 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
10696 (uchar *)&phy_addr, 1);
10697 phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
10698 AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
10699 (uchar *)&phy_size, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010700
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010701 asc_dvc->cfg->mcode_date =
10702 AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
10703 asc_dvc->cfg->mcode_version =
10704 AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010705
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010706 AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
10707 if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
10708 asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
10709 return (warn_code);
10710 }
10711 if (AscStartChip(iop_base) != 1) {
10712 asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
10713 return (warn_code);
10714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010715
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010716 return (warn_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010717}
10718
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010719static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010720{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010721 PortAddr iop_base;
10722 ushort q_addr;
10723 ushort saved_word;
10724 int sta;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010725
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010726 iop_base = asc_dvc->iop_base;
10727 sta = 0;
10728 q_addr = ASC_QNO_TO_QADDR(241);
10729 saved_word = AscReadLramWord(iop_base, q_addr);
10730 AscSetChipLramAddr(iop_base, q_addr);
10731 AscSetChipLramData(iop_base, 0x55AA);
10732 DvcSleepMilliSecond(10);
10733 AscSetChipLramAddr(iop_base, q_addr);
10734 if (AscGetChipLramData(iop_base) == 0x55AA) {
10735 sta = 1;
10736 AscWriteLramWord(iop_base, q_addr, saved_word);
10737 }
10738 return (sta);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010739}
10740
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010741static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010742{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010743 uchar read_back;
10744 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010746 retry = 0;
10747 while (TRUE) {
10748 AscSetChipEEPCmd(iop_base, cmd_reg);
10749 DvcSleepMilliSecond(1);
10750 read_back = AscGetChipEEPCmd(iop_base);
10751 if (read_back == cmd_reg) {
10752 return (1);
10753 }
10754 if (retry++ > ASC_EEP_MAX_RETRY) {
10755 return (0);
10756 }
10757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010758}
10759
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010760static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010761{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010762 ushort read_back;
10763 int retry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010764
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010765 retry = 0;
10766 while (TRUE) {
10767 AscSetChipEEPData(iop_base, data_reg);
10768 DvcSleepMilliSecond(1);
10769 read_back = AscGetChipEEPData(iop_base);
10770 if (read_back == data_reg) {
10771 return (1);
10772 }
10773 if (retry++ > ASC_EEP_MAX_RETRY) {
10774 return (0);
10775 }
10776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010777}
10778
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010779static void __devinit AscWaitEEPRead(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010780{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010781 DvcSleepMilliSecond(1);
10782 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010783}
10784
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010785static void __devinit AscWaitEEPWrite(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010786{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010787 DvcSleepMilliSecond(20);
10788 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010789}
10790
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010791static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010792{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010793 ushort read_wval;
10794 uchar cmd_reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010795
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010796 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10797 AscWaitEEPRead();
10798 cmd_reg = addr | ASC_EEP_CMD_READ;
10799 AscWriteEEPCmdReg(iop_base, cmd_reg);
10800 AscWaitEEPRead();
10801 read_wval = AscGetChipEEPData(iop_base);
10802 AscWaitEEPRead();
10803 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010804}
10805
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010806static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010807AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010808{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010809 ushort read_wval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010810
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010811 read_wval = AscReadEEPWord(iop_base, addr);
10812 if (read_wval != word_val) {
10813 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
10814 AscWaitEEPRead();
10815 AscWriteEEPDataReg(iop_base, word_val);
10816 AscWaitEEPRead();
10817 AscWriteEEPCmdReg(iop_base,
10818 (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
10819 AscWaitEEPWrite();
10820 AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
10821 AscWaitEEPRead();
10822 return (AscReadEEPWord(iop_base, addr));
10823 }
10824 return (read_wval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010825}
10826
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010827static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010828AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010829{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010830 ushort wval;
10831 ushort sum;
10832 ushort *wbuf;
10833 int cfg_beg;
10834 int cfg_end;
10835 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
10836 int s_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010837
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010838 wbuf = (ushort *)cfg_buf;
10839 sum = 0;
10840 /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
10841 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10842 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10843 sum += *wbuf;
10844 }
10845 if (bus_type & ASC_IS_VL) {
10846 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10847 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10848 } else {
10849 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10850 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10851 }
10852 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10853 wval = AscReadEEPWord(iop_base, (uchar)s_addr);
10854 if (s_addr <= uchar_end_in_config) {
10855 /*
10856 * Swap all char fields - must unswap bytes already swapped
10857 * by AscReadEEPWord().
10858 */
10859 *wbuf = le16_to_cpu(wval);
10860 } else {
10861 /* Don't swap word field at the end - cntl field. */
10862 *wbuf = wval;
10863 }
10864 sum += wval; /* Checksum treats all EEPROM data as words. */
10865 }
10866 /*
10867 * Read the checksum word which will be compared against 'sum'
10868 * by the caller. Word field already swapped.
10869 */
10870 *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
10871 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010872}
10873
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010874static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010875AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010876{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010877 int n_error;
10878 ushort *wbuf;
10879 ushort word;
10880 ushort sum;
10881 int s_addr;
10882 int cfg_beg;
10883 int cfg_end;
10884 int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010885
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010886 wbuf = (ushort *)cfg_buf;
10887 n_error = 0;
10888 sum = 0;
10889 /* Write two config words; AscWriteEEPWord() will swap bytes. */
10890 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10891 sum += *wbuf;
10892 if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10893 n_error++;
10894 }
10895 }
10896 if (bus_type & ASC_IS_VL) {
10897 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10898 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10899 } else {
10900 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10901 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10902 }
10903 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10904 if (s_addr <= uchar_end_in_config) {
10905 /*
10906 * This is a char field. Swap char fields before they are
10907 * swapped again by AscWriteEEPWord().
10908 */
10909 word = cpu_to_le16(*wbuf);
10910 if (word !=
10911 AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
10912 n_error++;
10913 }
10914 } else {
10915 /* Don't swap word field at the end - cntl field. */
10916 if (*wbuf !=
10917 AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
10918 n_error++;
10919 }
10920 }
10921 sum += *wbuf; /* Checksum calculated from word values. */
10922 }
10923 /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
10924 *wbuf = sum;
10925 if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
10926 n_error++;
10927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070010928
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010929 /* Read EEPROM back again. */
10930 wbuf = (ushort *)cfg_buf;
10931 /*
10932 * Read two config words; Byte-swapping done by AscReadEEPWord().
10933 */
10934 for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
10935 if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
10936 n_error++;
10937 }
10938 }
10939 if (bus_type & ASC_IS_VL) {
10940 cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
10941 cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
10942 } else {
10943 cfg_beg = ASC_EEP_DVC_CFG_BEG;
10944 cfg_end = ASC_EEP_MAX_DVC_ADDR;
10945 }
10946 for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
10947 if (s_addr <= uchar_end_in_config) {
10948 /*
10949 * Swap all char fields. Must unswap bytes already swapped
10950 * by AscReadEEPWord().
10951 */
10952 word =
10953 le16_to_cpu(AscReadEEPWord
10954 (iop_base, (uchar)s_addr));
10955 } else {
10956 /* Don't swap word field at the end - cntl field. */
10957 word = AscReadEEPWord(iop_base, (uchar)s_addr);
10958 }
10959 if (*wbuf != word) {
10960 n_error++;
10961 }
10962 }
10963 /* Read checksum; Byte swapping not needed. */
10964 if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
10965 n_error++;
10966 }
10967 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010968}
10969
Matthew Wilcox78e77d82007-07-29 21:46:15 -060010970static int __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010971AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010972{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010973 int retry;
10974 int n_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010975
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010976 retry = 0;
10977 while (TRUE) {
10978 if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
10979 bus_type)) == 0) {
10980 break;
10981 }
10982 if (++retry > ASC_EEP_MAX_RETRY) {
10983 break;
10984 }
10985 }
10986 return (n_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010987}
10988
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010989static void
10990AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010991{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010992 uchar dvc_type;
10993 ASC_SCSI_BIT_ID_TYPE tid_bits;
Linus Torvalds1da177e2005-04-16 15:20:36 -070010994
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010995 dvc_type = ASC_INQ_DVC_TYPE(inq);
10996 tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
Linus Torvalds1da177e2005-04-16 15:20:36 -070010997
Matthew Wilcox27c868c2007-07-26 10:56:23 -040010998 if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
10999 if (!(asc_dvc->init_sdtr & tid_bits)) {
11000 if ((dvc_type == TYPE_ROM) &&
11001 (AscCompareString((uchar *)inq->vendor_id,
11002 (uchar *)"HP ", 3) == 0)) {
11003 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
11004 }
11005 asc_dvc->pci_fix_asyn_xfer |= tid_bits;
11006 if ((dvc_type == TYPE_PROCESSOR) ||
11007 (dvc_type == TYPE_SCANNER) ||
11008 (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) {
11009 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
11010 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070011011
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011012 if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
11013 AscSetRunChipSynRegAtID(asc_dvc->iop_base,
11014 tid_no,
11015 ASYN_SDTR_DATA_FIX_PCI_REV_AB);
11016 }
11017 }
11018 }
11019 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011020}
11021
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011022static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011023{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011024 if ((inq->add_len >= 32) &&
11025 (AscCompareString((uchar *)inq->vendor_id,
11026 (uchar *)"QUANTUM XP34301", 15) == 0) &&
11027 (AscCompareString((uchar *)inq->product_rev_level,
11028 (uchar *)"1071", 4) == 0)) {
11029 return 0;
11030 }
11031 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011032}
11033
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011034static void
11035AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011036{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011037 ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
11038 ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011039
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011040 orig_init_sdtr = asc_dvc->init_sdtr;
11041 orig_use_tagged_qng = asc_dvc->use_tagged_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011042
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011043 asc_dvc->init_sdtr &= ~tid_bit;
11044 asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
11045 asc_dvc->use_tagged_qng &= ~tid_bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011046
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011047 if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
11048 if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
11049 asc_dvc->init_sdtr |= tid_bit;
11050 }
11051 if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
11052 ASC_INQ_CMD_QUEUE(inq)) {
11053 if (AscTagQueuingSafe(inq)) {
11054 asc_dvc->use_tagged_qng |= tid_bit;
11055 asc_dvc->cfg->can_tagged_qng |= tid_bit;
11056 }
11057 }
11058 }
11059 if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
11060 AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
11061 asc_dvc->cfg->disc_enable);
11062 AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
11063 asc_dvc->use_tagged_qng);
11064 AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
11065 asc_dvc->cfg->can_tagged_qng);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011066
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011067 asc_dvc->max_dvc_qng[tid_no] =
11068 asc_dvc->cfg->max_tag_qng[tid_no];
11069 AscWriteLramByte(asc_dvc->iop_base,
11070 (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no),
11071 asc_dvc->max_dvc_qng[tid_no]);
11072 }
11073 if (orig_init_sdtr != asc_dvc->init_sdtr) {
11074 AscAsyncFix(asc_dvc, tid_no, inq);
11075 }
11076 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011077}
11078
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011079static int AscCompareString(uchar *str1, uchar *str2, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011080{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011081 int i;
11082 int diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011083
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011084 for (i = 0; i < len; i++) {
11085 diff = (int)(str1[i] - str2[i]);
11086 if (diff != 0)
11087 return (diff);
11088 }
11089 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011090}
11091
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011092static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011093{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011094 uchar byte_data;
11095 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011096
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011097 if (isodd_word(addr)) {
11098 AscSetChipLramAddr(iop_base, addr - 1);
11099 word_data = AscGetChipLramData(iop_base);
11100 byte_data = (uchar)((word_data >> 8) & 0xFF);
11101 } else {
11102 AscSetChipLramAddr(iop_base, addr);
11103 word_data = AscGetChipLramData(iop_base);
11104 byte_data = (uchar)(word_data & 0xFF);
11105 }
11106 return (byte_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011107}
Linus Torvalds1da177e2005-04-16 15:20:36 -070011108
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011109static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
11110{
11111 ushort word_data;
11112
11113 AscSetChipLramAddr(iop_base, addr);
11114 word_data = AscGetChipLramData(iop_base);
11115 return (word_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011116}
11117
11118#if CC_VERY_LONG_SG_LIST
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011119static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011120{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011121 ushort val_low, val_high;
11122 ASC_DCNT dword_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011123
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011124 AscSetChipLramAddr(iop_base, addr);
11125 val_low = AscGetChipLramData(iop_base);
11126 val_high = AscGetChipLramData(iop_base);
11127 dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
11128 return (dword_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011129}
11130#endif /* CC_VERY_LONG_SG_LIST */
11131
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011132static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011133{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011134 AscSetChipLramAddr(iop_base, addr);
11135 AscSetChipLramData(iop_base, word_val);
11136 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011137}
11138
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011139static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011140{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011141 ushort word_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011142
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011143 if (isodd_word(addr)) {
11144 addr--;
11145 word_data = AscReadLramWord(iop_base, addr);
11146 word_data &= 0x00FF;
11147 word_data |= (((ushort)byte_val << 8) & 0xFF00);
11148 } else {
11149 word_data = AscReadLramWord(iop_base, addr);
11150 word_data &= 0xFF00;
11151 word_data |= ((ushort)byte_val & 0x00FF);
11152 }
11153 AscWriteLramWord(iop_base, addr, word_data);
11154 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011155}
11156
11157/*
11158 * Copy 2 bytes to LRAM.
11159 *
11160 * The source data is assumed to be in little-endian order in memory
11161 * and is maintained in little-endian order when written to LRAM.
11162 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011163static void
11164AscMemWordCopyPtrToLram(PortAddr iop_base,
11165 ushort s_addr, uchar *s_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011166{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011167 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011168
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011169 AscSetChipLramAddr(iop_base, s_addr);
11170 for (i = 0; i < 2 * words; i += 2) {
11171 /*
11172 * On a little-endian system the second argument below
11173 * produces a little-endian ushort which is written to
11174 * LRAM in little-endian order. On a big-endian system
11175 * the second argument produces a big-endian ushort which
11176 * is "transparently" byte-swapped by outpw() and written
11177 * in little-endian order to LRAM.
11178 */
11179 outpw(iop_base + IOP_RAM_DATA,
11180 ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
11181 }
11182 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011183}
11184
11185/*
11186 * Copy 4 bytes to LRAM.
11187 *
11188 * The source data is assumed to be in little-endian order in memory
11189 * and is maintained in little-endian order when writen to LRAM.
11190 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011191static void
11192AscMemDWordCopyPtrToLram(PortAddr iop_base,
11193 ushort s_addr, uchar *s_buffer, int dwords)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011194{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011195 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011196
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011197 AscSetChipLramAddr(iop_base, s_addr);
11198 for (i = 0; i < 4 * dwords; i += 4) {
11199 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
11200 outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
11201 }
11202 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011203}
11204
11205/*
11206 * Copy 2 bytes from LRAM.
11207 *
11208 * The source data is assumed to be in little-endian order in LRAM
11209 * and is maintained in little-endian order when written to memory.
11210 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011211static void
11212AscMemWordCopyPtrFromLram(PortAddr iop_base,
11213 ushort s_addr, uchar *d_buffer, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011214{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011215 int i;
11216 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011217
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011218 AscSetChipLramAddr(iop_base, s_addr);
11219 for (i = 0; i < 2 * words; i += 2) {
11220 word = inpw(iop_base + IOP_RAM_DATA);
11221 d_buffer[i] = word & 0xff;
11222 d_buffer[i + 1] = (word >> 8) & 0xff;
11223 }
11224 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011225}
11226
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011227static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011228{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011229 ASC_DCNT sum;
11230 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011231
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011232 sum = 0L;
11233 for (i = 0; i < words; i++, s_addr += 2) {
11234 sum += AscReadLramWord(iop_base, s_addr);
11235 }
11236 return (sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070011237}
11238
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011239static void
11240AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011241{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011242 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011243
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011244 AscSetChipLramAddr(iop_base, s_addr);
11245 for (i = 0; i < words; i++) {
11246 AscSetChipLramData(iop_base, set_wval);
11247 }
11248 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070011249}
11250
Linus Torvalds1da177e2005-04-16 15:20:36 -070011251/*
11252 * --- Adv Library Functions
11253 */
11254
11255/* a_mcode.h */
11256
11257/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011258static unsigned char _adv_asc3550_buf[] = {
11259 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
11260 0x01, 0x00, 0x48, 0xe4,
11261 0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
11262 0x28, 0x0e, 0x9e, 0xe7,
11263 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
11264 0x55, 0xf0, 0x01, 0xf6,
11265 0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
11266 0x00, 0xec, 0x85, 0xf0,
11267 0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
11268 0x86, 0xf0, 0xb4, 0x00,
11269 0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
11270 0xaa, 0x18, 0x02, 0x80,
11271 0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
11272 0x00, 0x57, 0x01, 0xea,
11273 0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
11274 0x03, 0xe6, 0xb6, 0x00,
11275 0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
11276 0x02, 0x4a, 0xb9, 0x54,
11277 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
11278 0x3e, 0x00, 0x80, 0x00,
11279 0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
11280 0x74, 0x01, 0x76, 0x01,
11281 0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
11282 0x4c, 0x1c, 0xbb, 0x55,
11283 0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
11284 0x03, 0xf7, 0x06, 0xf7,
11285 0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
11286 0x30, 0x13, 0x64, 0x15,
11287 0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
11288 0x04, 0xea, 0x5d, 0xf0,
11289 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
11290 0xcc, 0x00, 0x20, 0x01,
11291 0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
11292 0x40, 0x13, 0x30, 0x1c,
11293 0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11294 0x59, 0xf0, 0xa7, 0xf0,
11295 0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
11296 0xa4, 0x00, 0xb5, 0x00,
11297 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
11298 0x14, 0x0e, 0x02, 0x10,
11299 0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
11300 0x10, 0x15, 0x14, 0x15,
11301 0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
11302 0x91, 0x44, 0x0a, 0x45,
11303 0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
11304 0x83, 0x59, 0x05, 0xe6,
11305 0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
11306 0x02, 0xfa, 0x03, 0xfa,
11307 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
11308 0x9e, 0x00, 0xa8, 0x00,
11309 0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
11310 0x7a, 0x01, 0xc0, 0x01,
11311 0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
11312 0x69, 0x08, 0xba, 0x08,
11313 0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
11314 0xf1, 0x10, 0x06, 0x12,
11315 0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
11316 0x8a, 0x15, 0xc6, 0x17,
11317 0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
11318 0x0e, 0x47, 0x48, 0x47,
11319 0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
11320 0x14, 0x56, 0x77, 0x57,
11321 0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
11322 0xf0, 0x29, 0x02, 0xfe,
11323 0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
11324 0xfe, 0x80, 0x01, 0xff,
11325 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11326 0x00, 0xfe, 0x57, 0x24,
11327 0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
11328 0x00, 0x00, 0xff, 0x08,
11329 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11330 0xff, 0xff, 0xff, 0x0f,
11331 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11332 0xfe, 0x04, 0xf7, 0xcf,
11333 0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
11334 0x0b, 0x3c, 0x2a, 0xfe,
11335 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
11336 0xfe, 0xf0, 0x01, 0xfe,
11337 0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
11338 0x02, 0xfe, 0xd4, 0x0c,
11339 0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11340 0x1c, 0x05, 0xfe, 0xa6,
11341 0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
11342 0xf0, 0xfe, 0x86, 0x02,
11343 0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
11344 0xfe, 0x46, 0xf0, 0xfe,
11345 0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11346 0x44, 0x02, 0xfe, 0x44,
11347 0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
11348 0xa0, 0x17, 0x06, 0x18,
11349 0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
11350 0x1e, 0x1c, 0xfe, 0xe9,
11351 0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
11352 0x0a, 0x6b, 0x01, 0x9e,
11353 0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
11354 0x01, 0x82, 0xfe, 0xbd,
11355 0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11356 0x58, 0x1c, 0x17, 0x06,
11357 0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
11358 0xfe, 0x94, 0x02, 0xfe,
11359 0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
11360 0x01, 0xfe, 0x54, 0x0f,
11361 0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
11362 0x69, 0x10, 0x17, 0x06,
11363 0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
11364 0xf6, 0xc7, 0x01, 0xfe,
11365 0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
11366 0x02, 0x29, 0x0a, 0x40,
11367 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
11368 0x58, 0x0a, 0x99, 0x01,
11369 0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
11370 0x2a, 0x46, 0xfe, 0x02,
11371 0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
11372 0x01, 0xfe, 0x07, 0x4b,
11373 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
11374 0xfe, 0x56, 0x03, 0xfe,
11375 0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
11376 0xfe, 0x9f, 0xf0, 0xfe,
11377 0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
11378 0x1c, 0xeb, 0x09, 0x04,
11379 0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
11380 0x01, 0x0e, 0xac, 0x75,
11381 0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
11382 0xfe, 0x82, 0xf0, 0xfe,
11383 0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
11384 0x32, 0x1f, 0xfe, 0xb4,
11385 0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
11386 0x0a, 0xf0, 0xfe, 0x7a,
11387 0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
11388 0x01, 0x33, 0x8f, 0xfe,
11389 0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
11390 0xf7, 0xfe, 0x48, 0x1c,
11391 0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
11392 0x0a, 0xca, 0x01, 0x0e,
11393 0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
11394 0x2c, 0x01, 0x33, 0x8f,
11395 0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
11396 0xfe, 0x3c, 0x04, 0x1f,
11397 0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
11398 0x12, 0x2b, 0xff, 0x02,
11399 0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
11400 0x22, 0x30, 0x2e, 0xd5,
11401 0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
11402 0xfe, 0x4c, 0x54, 0x64,
11403 0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
11404 0xfe, 0x2a, 0x13, 0x2f,
11405 0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
11406 0xd3, 0xfa, 0xef, 0x86,
11407 0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
11408 0x1d, 0xfe, 0x1c, 0x12,
11409 0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
11410 0x70, 0x0c, 0x02, 0x22,
11411 0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
11412 0x01, 0x33, 0x02, 0x29,
11413 0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
11414 0x80, 0xfe, 0x31, 0xe4,
11415 0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
11416 0xfe, 0x70, 0x12, 0x49,
11417 0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
11418 0x80, 0x05, 0xfe, 0x31,
11419 0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
11420 0x28, 0xfe, 0x42, 0x12,
11421 0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
11422 0x11, 0xfe, 0xe3, 0x00,
11423 0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
11424 0x64, 0x05, 0x83, 0x24,
11425 0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
11426 0x09, 0x48, 0x01, 0x08,
11427 0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
11428 0x86, 0x24, 0x06, 0x12,
11429 0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
11430 0x01, 0xa7, 0x14, 0x92,
11431 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
11432 0x02, 0x22, 0x05, 0xfe,
11433 0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
11434 0x47, 0x01, 0xa7, 0x26,
11435 0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
11436 0x01, 0xfe, 0xaa, 0x14,
11437 0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
11438 0x05, 0x50, 0xb4, 0x0c,
11439 0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
11440 0x13, 0x01, 0xfe, 0x14,
11441 0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
11442 0xff, 0x02, 0x00, 0x57,
11443 0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
11444 0x72, 0x06, 0x49, 0x04,
11445 0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
11446 0x06, 0x11, 0x9a, 0x01,
11447 0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
11448 0x01, 0xa7, 0xec, 0x72,
11449 0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
11450 0xfe, 0x0a, 0xf0, 0xfe,
11451 0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
11452 0x8d, 0x81, 0x02, 0x22,
11453 0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
11454 0x01, 0x08, 0x15, 0x00,
11455 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
11456 0x00, 0x02, 0xfe, 0x32,
11457 0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
11458 0xfe, 0x1b, 0x00, 0x01,
11459 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
11460 0x08, 0x15, 0x06, 0x01,
11461 0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
11462 0x9a, 0x81, 0x4b, 0x1d,
11463 0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
11464 0x45, 0xfe, 0x32, 0x12,
11465 0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
11466 0xfe, 0x32, 0x07, 0x8d,
11467 0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
11468 0x06, 0x15, 0x19, 0x02,
11469 0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
11470 0x90, 0x77, 0xfe, 0xca,
11471 0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
11472 0x10, 0xfe, 0x0e, 0x12,
11473 0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
11474 0x83, 0xe7, 0xc4, 0xa1,
11475 0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
11476 0x40, 0x12, 0x58, 0x01,
11477 0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
11478 0x51, 0x83, 0xfb, 0xfe,
11479 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
11480 0xfe, 0x40, 0x50, 0xfe,
11481 0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
11482 0xfe, 0x2a, 0x12, 0xfe,
11483 0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
11484 0x85, 0x01, 0xa8, 0xfe,
11485 0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
11486 0x18, 0x57, 0xfb, 0xfe,
11487 0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
11488 0x0c, 0x39, 0x18, 0x3a,
11489 0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
11490 0x11, 0x65, 0xfe, 0x48,
11491 0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
11492 0xdd, 0xb8, 0xfe, 0x80,
11493 0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
11494 0xfe, 0x7a, 0x08, 0x8d,
11495 0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
11496 0x10, 0x61, 0x04, 0x06,
11497 0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
11498 0x12, 0xfe, 0x2e, 0x1c,
11499 0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
11500 0x52, 0x12, 0xfe, 0x2c,
11501 0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
11502 0x08, 0xfe, 0x8a, 0x10,
11503 0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
11504 0x24, 0x0a, 0xab, 0xfe,
11505 0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
11506 0x1c, 0x12, 0xb5, 0xfe,
11507 0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
11508 0x1c, 0x06, 0x16, 0x9d,
11509 0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
11510 0x14, 0x92, 0x01, 0x33,
11511 0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
11512 0xfe, 0x74, 0x18, 0x1c,
11513 0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
11514 0x01, 0xe6, 0x1e, 0x27,
11515 0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
11516 0x09, 0x04, 0x6a, 0xfe,
11517 0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
11518 0xfe, 0x83, 0x80, 0xfe,
11519 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
11520 0x27, 0xfe, 0x40, 0x59,
11521 0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
11522 0x7c, 0xbe, 0x54, 0xbf,
11523 0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
11524 0x79, 0x56, 0x68, 0x57,
11525 0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
11526 0xa2, 0x23, 0x0c, 0x7b,
11527 0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
11528 0x16, 0xd7, 0x79, 0x39,
11529 0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
11530 0xfe, 0x10, 0x58, 0xfe,
11531 0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
11532 0x19, 0x16, 0xd7, 0x09,
11533 0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
11534 0xfe, 0x10, 0x90, 0xfe,
11535 0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
11536 0x11, 0x9b, 0x09, 0x04,
11537 0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
11538 0xfe, 0x0c, 0x58, 0xfe,
11539 0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
11540 0x0b, 0xfe, 0x1a, 0x12,
11541 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
11542 0x14, 0x7a, 0x01, 0x33,
11543 0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
11544 0xfe, 0xed, 0x19, 0xbf,
11545 0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
11546 0x34, 0xfe, 0x74, 0x10,
11547 0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
11548 0x84, 0x05, 0xcb, 0x1c,
11549 0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
11550 0xf0, 0xfe, 0xc4, 0x0a,
11551 0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
11552 0xce, 0xf0, 0xfe, 0xca,
11553 0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
11554 0x22, 0x00, 0x02, 0x5a,
11555 0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
11556 0xfe, 0xd0, 0xf0, 0xfe,
11557 0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
11558 0x4c, 0xfe, 0x10, 0x10,
11559 0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
11560 0x2a, 0x13, 0xfe, 0x4e,
11561 0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
11562 0x16, 0x32, 0x2a, 0x73,
11563 0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
11564 0x32, 0x8c, 0xfe, 0x48,
11565 0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
11566 0xdb, 0x10, 0x11, 0xfe,
11567 0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
11568 0x22, 0x30, 0x2e, 0xd8,
11569 0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
11570 0x45, 0x0f, 0xfe, 0x42,
11571 0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
11572 0x09, 0x04, 0x0b, 0xfe,
11573 0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
11574 0x00, 0x21, 0xfe, 0xa6,
11575 0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
11576 0xfe, 0xe2, 0x10, 0x01,
11577 0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
11578 0x01, 0x6f, 0x02, 0x29,
11579 0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
11580 0x01, 0x86, 0x3e, 0x0b,
11581 0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
11582 0x3e, 0x0b, 0x0f, 0xfe,
11583 0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
11584 0xe8, 0x59, 0x11, 0x2d,
11585 0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
11586 0x04, 0x0b, 0x84, 0x3e,
11587 0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
11588 0x09, 0x04, 0x1b, 0xfe,
11589 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
11590 0x1c, 0x1c, 0xfe, 0x9d,
11591 0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
11592 0xfe, 0x15, 0x00, 0xfe,
11593 0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
11594 0x0f, 0xfe, 0x47, 0x00,
11595 0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
11596 0xab, 0x70, 0x05, 0x6b,
11597 0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
11598 0x1c, 0x42, 0x59, 0x01,
11599 0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
11600 0x00, 0x37, 0x97, 0x01,
11601 0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
11602 0x1d, 0xfe, 0xce, 0x45,
11603 0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
11604 0x57, 0x05, 0x51, 0xfe,
11605 0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
11606 0x46, 0x09, 0x04, 0x1d,
11607 0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
11608 0x99, 0x01, 0x0e, 0xfe,
11609 0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
11610 0xfe, 0xee, 0x14, 0xee,
11611 0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
11612 0x13, 0x02, 0x29, 0x1e,
11613 0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
11614 0xce, 0x1e, 0x2d, 0x47,
11615 0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
11616 0x12, 0x4d, 0x01, 0xfe,
11617 0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
11618 0xf0, 0x0d, 0xfe, 0x02,
11619 0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
11620 0xf6, 0xfe, 0x34, 0x01,
11621 0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
11622 0xaf, 0xfe, 0x02, 0xea,
11623 0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
11624 0x05, 0xfe, 0x38, 0x01,
11625 0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
11626 0x0c, 0xfe, 0x62, 0x01,
11627 0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
11628 0x03, 0x23, 0x03, 0x1e,
11629 0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
11630 0x71, 0x13, 0xfe, 0x24,
11631 0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
11632 0xdc, 0xfe, 0x73, 0x57,
11633 0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
11634 0x80, 0x5d, 0x03, 0xfe,
11635 0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
11636 0x75, 0x03, 0x09, 0x04,
11637 0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
11638 0xfe, 0x1e, 0x80, 0xe1,
11639 0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
11640 0x90, 0xa3, 0xfe, 0x3c,
11641 0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
11642 0x16, 0x2f, 0x07, 0x2d,
11643 0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
11644 0xe8, 0x11, 0xfe, 0xe9,
11645 0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
11646 0x1e, 0x1c, 0xfe, 0x14,
11647 0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
11648 0x09, 0x04, 0x4f, 0xfe,
11649 0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
11650 0x40, 0x12, 0x20, 0x63,
11651 0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
11652 0x1c, 0x05, 0xfe, 0xac,
11653 0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
11654 0xfe, 0xb0, 0x00, 0xfe,
11655 0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
11656 0x24, 0x69, 0x12, 0xc9,
11657 0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
11658 0x90, 0x4d, 0xfe, 0x91,
11659 0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
11660 0xfe, 0x90, 0x4d, 0xfe,
11661 0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
11662 0x46, 0x1e, 0x20, 0xed,
11663 0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
11664 0x70, 0xfe, 0x14, 0x1c,
11665 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
11666 0xfe, 0x07, 0xe6, 0x1d,
11667 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
11668 0xfa, 0xef, 0xfe, 0x42,
11669 0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
11670 0xfe, 0x36, 0x12, 0xf0,
11671 0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
11672 0x3d, 0x75, 0x07, 0x10,
11673 0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
11674 0x10, 0x07, 0x7e, 0x45,
11675 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
11676 0xfe, 0x01, 0xec, 0x97,
11677 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
11678 0x27, 0x01, 0xda, 0xfe,
11679 0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
11680 0xfe, 0x48, 0x12, 0x07,
11681 0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
11682 0xfe, 0x3e, 0x11, 0x07,
11683 0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
11684 0x11, 0x07, 0x19, 0xfe,
11685 0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
11686 0x01, 0x08, 0x8c, 0x43,
11687 0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
11688 0x7e, 0x02, 0x29, 0x2b,
11689 0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
11690 0xfc, 0x10, 0x09, 0x04,
11691 0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
11692 0xc6, 0x10, 0x1e, 0x58,
11693 0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
11694 0x54, 0x18, 0x55, 0x23,
11695 0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
11696 0xa5, 0xc0, 0x38, 0xc1,
11697 0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
11698 0x05, 0xfa, 0x4e, 0xfe,
11699 0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
11700 0x0c, 0x56, 0x18, 0x57,
11701 0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
11702 0x00, 0x56, 0xfe, 0xa1,
11703 0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
11704 0x58, 0xfe, 0x1f, 0x40,
11705 0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
11706 0x31, 0x57, 0xfe, 0x44,
11707 0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
11708 0x8a, 0x50, 0x05, 0x39,
11709 0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
11710 0x12, 0xcd, 0x02, 0x5b,
11711 0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
11712 0x2f, 0x07, 0x9b, 0x21,
11713 0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
11714 0x39, 0x68, 0x3a, 0xfe,
11715 0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
11716 0x51, 0xfe, 0x8e, 0x51,
11717 0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
11718 0x01, 0x08, 0x25, 0x32,
11719 0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
11720 0x3b, 0x02, 0x44, 0x01,
11721 0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
11722 0x01, 0x08, 0x1f, 0xa2,
11723 0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
11724 0x00, 0x28, 0x84, 0x49,
11725 0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
11726 0x78, 0x3d, 0xfe, 0xda,
11727 0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
11728 0x05, 0xc6, 0x28, 0x84,
11729 0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
11730 0x14, 0xfe, 0x03, 0x17,
11731 0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
11732 0xfe, 0xaa, 0x14, 0x02,
11733 0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
11734 0x21, 0x44, 0x01, 0xfe,
11735 0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
11736 0xfe, 0x4a, 0xf4, 0x0b,
11737 0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
11738 0x85, 0x02, 0x5b, 0x05,
11739 0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
11740 0xd8, 0x14, 0x02, 0x5c,
11741 0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
11742 0x01, 0x08, 0x23, 0x72,
11743 0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
11744 0x12, 0x5e, 0x2b, 0x01,
11745 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
11746 0x1c, 0xfe, 0xff, 0x7f,
11747 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
11748 0x57, 0x48, 0x8b, 0x1c,
11749 0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
11750 0x00, 0x57, 0x48, 0x8b,
11751 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
11752 0x03, 0x0a, 0x50, 0x01,
11753 0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
11754 0x54, 0xfe, 0x00, 0xf4,
11755 0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
11756 0x03, 0x7c, 0x63, 0x27,
11757 0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
11758 0xfe, 0x82, 0x4a, 0xfe,
11759 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
11760 0x42, 0x48, 0x5f, 0x60,
11761 0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
11762 0x1f, 0xfe, 0xa2, 0x14,
11763 0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
11764 0xcc, 0x12, 0x49, 0x04,
11765 0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
11766 0xe8, 0x13, 0x3b, 0x13,
11767 0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
11768 0xa1, 0xff, 0x02, 0x83,
11769 0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
11770 0x13, 0x06, 0xfe, 0x56,
11771 0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
11772 0x64, 0x00, 0x17, 0x93,
11773 0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
11774 0xc8, 0x00, 0x8e, 0xe4,
11775 0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
11776 0x01, 0xba, 0xfe, 0x4e,
11777 0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
11778 0xfe, 0x60, 0x14, 0xfe,
11779 0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
11780 0xfe, 0x22, 0x13, 0x1c,
11781 0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
11782 0xfe, 0x9c, 0x14, 0xb7,
11783 0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
11784 0xfe, 0x9c, 0x14, 0xb7,
11785 0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
11786 0xfe, 0xb4, 0x56, 0xfe,
11787 0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
11788 0xe5, 0x15, 0x0b, 0x01,
11789 0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
11790 0x49, 0x01, 0x08, 0x03,
11791 0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
11792 0x15, 0x06, 0x01, 0x08,
11793 0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
11794 0x4a, 0x01, 0x08, 0x03,
11795 0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
11796 0xfe, 0x49, 0xf4, 0x00,
11797 0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
11798 0x08, 0x2f, 0x07, 0xfe,
11799 0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
11800 0x01, 0x43, 0x1e, 0xcd,
11801 0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11802 0xed, 0x88, 0x07, 0x10,
11803 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
11804 0x80, 0x01, 0x0e, 0x88,
11805 0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
11806 0x88, 0x03, 0x0a, 0x42,
11807 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
11808 0xfe, 0x80, 0x80, 0xf2,
11809 0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
11810 0x01, 0x82, 0x03, 0x17,
11811 0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
11812 0xfe, 0x24, 0x1c, 0xfe,
11813 0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
11814 0x91, 0x1d, 0x66, 0xfe,
11815 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
11816 0xda, 0x10, 0x17, 0x10,
11817 0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
11818 0x05, 0xfe, 0x66, 0x01,
11819 0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
11820 0xfe, 0x3c, 0x50, 0x66,
11821 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
11822 0x40, 0x16, 0xfe, 0xb6,
11823 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
11824 0x10, 0x71, 0xfe, 0x83,
11825 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
11826 0xfe, 0x62, 0x16, 0xfe,
11827 0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
11828 0xfe, 0x98, 0xe7, 0x00,
11829 0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
11830 0xfe, 0x30, 0xbc, 0xfe,
11831 0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
11832 0xc5, 0x90, 0xfe, 0x9a,
11833 0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
11834 0x42, 0x10, 0xfe, 0x02,
11835 0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
11836 0xfe, 0x1d, 0xf7, 0x4f,
11837 0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
11838 0x47, 0xfe, 0x83, 0x58,
11839 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
11840 0xfe, 0xdd, 0x00, 0x63,
11841 0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
11842 0x06, 0x37, 0x95, 0xa9,
11843 0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
11844 0x18, 0x1c, 0x1a, 0x5d,
11845 0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
11846 0xe1, 0x10, 0x78, 0x2c,
11847 0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
11848 0x13, 0x3c, 0x8a, 0x0a,
11849 0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
11850 0xe3, 0xfe, 0x00, 0xcc,
11851 0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
11852 0x0e, 0xf2, 0x01, 0x6f,
11853 0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
11854 0xf6, 0xfe, 0xd6, 0xf0,
11855 0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
11856 0x15, 0x00, 0x59, 0x76,
11857 0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
11858 0x11, 0x2d, 0x01, 0x6f,
11859 0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
11860 0xc8, 0xfe, 0x48, 0x55,
11861 0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
11862 0x99, 0x01, 0x0e, 0xf0,
11863 0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
11864 0x75, 0x03, 0x0a, 0x42,
11865 0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
11866 0x0e, 0x73, 0x75, 0x03,
11867 0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
11868 0xfe, 0x3a, 0x45, 0x5b,
11869 0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
11870 0xfe, 0x02, 0xe6, 0x1b,
11871 0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
11872 0xfe, 0x94, 0x00, 0xfe,
11873 0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
11874 0xe6, 0x2c, 0xfe, 0x4e,
11875 0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
11876 0x03, 0x07, 0x7a, 0xfe,
11877 0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
11878 0x07, 0x1b, 0xfe, 0x5a,
11879 0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
11880 0x24, 0x2c, 0xdc, 0x07,
11881 0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
11882 0x9f, 0xad, 0x03, 0x14,
11883 0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
11884 0x03, 0x25, 0xfe, 0xca,
11885 0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
11886 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070011887};
11888
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011889static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf); /* 0x13AD */
11890static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011891
11892/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040011893static unsigned char _adv_asc38C0800_buf[] = {
11894 0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
11895 0x01, 0x00, 0x48, 0xe4,
11896 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
11897 0x1c, 0x0f, 0x00, 0xf6,
11898 0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
11899 0x09, 0xe7, 0x55, 0xf0,
11900 0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
11901 0x18, 0xf4, 0x08, 0x00,
11902 0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
11903 0x86, 0xf0, 0xb1, 0xf0,
11904 0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
11905 0x3c, 0x00, 0xbb, 0x00,
11906 0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
11907 0xba, 0x13, 0x18, 0x40,
11908 0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
11909 0x6e, 0x01, 0x74, 0x01,
11910 0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
11911 0xc0, 0x00, 0x01, 0x01,
11912 0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
11913 0x08, 0x12, 0x02, 0x4a,
11914 0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
11915 0x5d, 0xf0, 0x02, 0xfa,
11916 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
11917 0x68, 0x01, 0x6a, 0x01,
11918 0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
11919 0x06, 0x13, 0x4c, 0x1c,
11920 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
11921 0x0f, 0x00, 0x47, 0x00,
11922 0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
11923 0x4e, 0x1c, 0x10, 0x44,
11924 0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
11925 0x05, 0x00, 0x34, 0x00,
11926 0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
11927 0x42, 0x0c, 0x12, 0x0f,
11928 0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
11929 0x00, 0x4e, 0x42, 0x54,
11930 0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
11931 0x59, 0xf0, 0xb8, 0xf0,
11932 0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
11933 0x19, 0x00, 0x33, 0x00,
11934 0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
11935 0xe7, 0x00, 0xe2, 0x03,
11936 0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
11937 0x12, 0x13, 0x24, 0x14,
11938 0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
11939 0x36, 0x1c, 0x08, 0x44,
11940 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
11941 0x3a, 0x55, 0x83, 0x55,
11942 0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
11943 0x0c, 0xf0, 0x04, 0xf8,
11944 0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
11945 0xa8, 0x00, 0xaa, 0x00,
11946 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
11947 0xc4, 0x01, 0xc6, 0x01,
11948 0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
11949 0x68, 0x08, 0x69, 0x08,
11950 0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
11951 0xed, 0x10, 0xf1, 0x10,
11952 0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
11953 0x1e, 0x13, 0x46, 0x14,
11954 0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
11955 0xca, 0x18, 0xe6, 0x19,
11956 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
11957 0xf0, 0x2b, 0x02, 0xfe,
11958 0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
11959 0xfe, 0x84, 0x01, 0xff,
11960 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
11961 0x00, 0xfe, 0x57, 0x24,
11962 0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
11963 0x00, 0x00, 0xff, 0x08,
11964 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
11965 0xff, 0xff, 0xff, 0x11,
11966 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
11967 0xfe, 0x04, 0xf7, 0xd6,
11968 0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
11969 0x0a, 0x42, 0x2c, 0xfe,
11970 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
11971 0xfe, 0xf4, 0x01, 0xfe,
11972 0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
11973 0x02, 0xfe, 0xc8, 0x0d,
11974 0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
11975 0x1c, 0x03, 0xfe, 0xa6,
11976 0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
11977 0xf0, 0xfe, 0x8a, 0x02,
11978 0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
11979 0xfe, 0x46, 0xf0, 0xfe,
11980 0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
11981 0x48, 0x02, 0xfe, 0x44,
11982 0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
11983 0xaa, 0x18, 0x06, 0x14,
11984 0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
11985 0x1e, 0x1c, 0xfe, 0xe9,
11986 0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
11987 0x09, 0x70, 0x01, 0xa8,
11988 0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
11989 0x01, 0x87, 0xfe, 0xbd,
11990 0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
11991 0x58, 0x1c, 0x18, 0x06,
11992 0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
11993 0xfe, 0x98, 0x02, 0xfe,
11994 0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
11995 0x01, 0xfe, 0x48, 0x10,
11996 0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
11997 0x69, 0x10, 0x18, 0x06,
11998 0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
11999 0xf6, 0xce, 0x01, 0xfe,
12000 0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
12001 0x82, 0x16, 0x02, 0x2b,
12002 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
12003 0xfe, 0x41, 0x58, 0x09,
12004 0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
12005 0x82, 0x16, 0x02, 0x2b,
12006 0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
12007 0xfe, 0x77, 0x57, 0xfe,
12008 0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
12009 0xfe, 0x40, 0x1c, 0x1c,
12010 0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
12011 0x03, 0xfe, 0x11, 0xf0,
12012 0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
12013 0xfe, 0x11, 0x00, 0x02,
12014 0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
12015 0x21, 0x22, 0xa3, 0xb7,
12016 0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
12017 0x12, 0xd1, 0x1c, 0xd9,
12018 0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
12019 0xfe, 0xe4, 0x00, 0x27,
12020 0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
12021 0x06, 0xf0, 0xfe, 0xc8,
12022 0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
12023 0x70, 0x28, 0x17, 0xfe,
12024 0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
12025 0xf9, 0x2c, 0x99, 0x19,
12026 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
12027 0x74, 0x01, 0xaf, 0x8c,
12028 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
12029 0x8d, 0x51, 0x64, 0x79,
12030 0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
12031 0xfe, 0x6a, 0x02, 0x02,
12032 0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
12033 0xfe, 0x3c, 0x04, 0x3b,
12034 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
12035 0x00, 0x10, 0x01, 0x0b,
12036 0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
12037 0xfe, 0x4c, 0x44, 0xfe,
12038 0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
12039 0xda, 0x4f, 0x79, 0x2a,
12040 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
12041 0xfe, 0x2a, 0x13, 0x32,
12042 0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
12043 0x54, 0x6b, 0xda, 0xfe,
12044 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
12045 0x08, 0x13, 0x32, 0x07,
12046 0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
12047 0x08, 0x05, 0x06, 0x4d,
12048 0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
12049 0x2d, 0x12, 0xfe, 0xe6,
12050 0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
12051 0x02, 0x2b, 0xfe, 0x42,
12052 0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12053 0xfe, 0x87, 0x80, 0xfe,
12054 0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
12055 0x07, 0x19, 0xfe, 0x7c,
12056 0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
12057 0x17, 0xfe, 0x90, 0x05,
12058 0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
12059 0xa0, 0x00, 0x28, 0xfe,
12060 0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
12061 0x34, 0xfe, 0x89, 0x48,
12062 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
12063 0x12, 0xfe, 0xe3, 0x00,
12064 0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
12065 0x70, 0x05, 0x88, 0x25,
12066 0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
12067 0x09, 0x48, 0xff, 0x02,
12068 0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
12069 0x08, 0x53, 0x05, 0xcb,
12070 0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
12071 0x05, 0x1b, 0xfe, 0x22,
12072 0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
12073 0x0d, 0x00, 0x01, 0x36,
12074 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
12075 0x03, 0x5c, 0x28, 0xfe,
12076 0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
12077 0x05, 0x1f, 0xfe, 0x02,
12078 0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
12079 0x01, 0x4b, 0x12, 0xfe,
12080 0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
12081 0x12, 0x03, 0x45, 0x28,
12082 0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
12083 0x43, 0x48, 0xc4, 0xcc,
12084 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
12085 0x6e, 0x41, 0x01, 0xb2,
12086 0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
12087 0xfe, 0xcc, 0x15, 0x1d,
12088 0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
12089 0x45, 0xc1, 0x0c, 0x45,
12090 0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
12091 0xe2, 0x00, 0x27, 0xdb,
12092 0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
12093 0xfe, 0x06, 0xf0, 0xfe,
12094 0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
12095 0x16, 0x19, 0x01, 0x0b,
12096 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
12097 0xfe, 0x99, 0xa4, 0x01,
12098 0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
12099 0x12, 0x08, 0x05, 0x1a,
12100 0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
12101 0x0b, 0x16, 0x00, 0x01,
12102 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
12103 0xe2, 0x6c, 0x58, 0xbe,
12104 0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
12105 0xfe, 0x09, 0x6f, 0xba,
12106 0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
12107 0xfe, 0x54, 0x07, 0x1c,
12108 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
12109 0x07, 0x02, 0x24, 0x01,
12110 0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
12111 0x2c, 0x90, 0xfe, 0xae,
12112 0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
12113 0x37, 0x22, 0x20, 0x07,
12114 0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
12115 0xfe, 0x06, 0x10, 0xfe,
12116 0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
12117 0x37, 0x01, 0xb3, 0xb8,
12118 0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
12119 0x50, 0xfe, 0x44, 0x51,
12120 0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
12121 0x14, 0x5f, 0xfe, 0x0c,
12122 0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
12123 0x14, 0x3e, 0xfe, 0x4a,
12124 0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
12125 0x90, 0x0c, 0x60, 0x14,
12126 0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
12127 0xfe, 0x44, 0x90, 0xfe,
12128 0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
12129 0x0c, 0x5e, 0x14, 0x5f,
12130 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
12131 0x14, 0x3c, 0x21, 0x0c,
12132 0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
12133 0x27, 0xdd, 0xfe, 0x9e,
12134 0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
12135 0x9a, 0x08, 0xc6, 0xfe,
12136 0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
12137 0x95, 0x86, 0x02, 0x24,
12138 0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
12139 0x06, 0xfe, 0x10, 0x12,
12140 0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
12141 0x1c, 0x02, 0xfe, 0x18,
12142 0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
12143 0x2c, 0x1c, 0xfe, 0xaa,
12144 0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
12145 0xde, 0x09, 0xfe, 0xb7,
12146 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
12147 0xfe, 0xf1, 0x18, 0xfe,
12148 0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
12149 0x14, 0x59, 0xfe, 0x95,
12150 0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
12151 0xfe, 0xf0, 0x08, 0xb5,
12152 0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
12153 0x0b, 0xb6, 0xfe, 0xbf,
12154 0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
12155 0x12, 0xc2, 0xfe, 0xd2,
12156 0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
12157 0x06, 0x17, 0x85, 0xc5,
12158 0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
12159 0x9d, 0x01, 0x36, 0x10,
12160 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
12161 0x98, 0x80, 0xfe, 0x19,
12162 0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
12163 0xfe, 0x44, 0x54, 0xbe,
12164 0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
12165 0x02, 0x4a, 0x08, 0x05,
12166 0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
12167 0x9c, 0x3c, 0xfe, 0x6c,
12168 0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
12169 0x3b, 0x40, 0x03, 0x49,
12170 0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
12171 0x8f, 0xfe, 0xe3, 0x54,
12172 0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
12173 0xda, 0x09, 0xfe, 0x8b,
12174 0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
12175 0x0a, 0x3a, 0x49, 0x3b,
12176 0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
12177 0xad, 0xfe, 0x01, 0x59,
12178 0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
12179 0x49, 0x8f, 0xfe, 0xe3,
12180 0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
12181 0x4a, 0x3a, 0x49, 0x3b,
12182 0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
12183 0x02, 0x4a, 0x08, 0x05,
12184 0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
12185 0xb7, 0xfe, 0x03, 0xa1,
12186 0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
12187 0xfe, 0x86, 0x91, 0x6a,
12188 0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
12189 0x61, 0x0c, 0x7f, 0x14,
12190 0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
12191 0x9b, 0x2e, 0x9c, 0x3c,
12192 0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
12193 0xfa, 0x3c, 0x01, 0xef,
12194 0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
12195 0xe4, 0x08, 0x05, 0x1f,
12196 0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
12197 0x03, 0x5e, 0x29, 0x5f,
12198 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
12199 0xf4, 0x09, 0x08, 0x05,
12200 0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
12201 0x81, 0x50, 0xfe, 0x10,
12202 0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
12203 0x08, 0x09, 0x12, 0xa6,
12204 0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
12205 0x08, 0x09, 0xfe, 0x0c,
12206 0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
12207 0x08, 0x05, 0x0a, 0xfe,
12208 0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
12209 0xf0, 0xe2, 0x15, 0x7e,
12210 0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
12211 0x57, 0x3d, 0xfe, 0xed,
12212 0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
12213 0x00, 0xff, 0x35, 0xfe,
12214 0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
12215 0x1e, 0x19, 0x8a, 0x03,
12216 0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
12217 0xfe, 0xd1, 0xf0, 0xfe,
12218 0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
12219 0x10, 0xfe, 0xce, 0xf0,
12220 0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
12221 0x10, 0xfe, 0x22, 0x00,
12222 0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
12223 0x02, 0x65, 0xfe, 0xd0,
12224 0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
12225 0x0b, 0x10, 0x58, 0xfe,
12226 0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
12227 0x12, 0x00, 0x2c, 0x0f,
12228 0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
12229 0x0c, 0xbc, 0x17, 0x34,
12230 0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
12231 0x0c, 0x1c, 0x34, 0x94,
12232 0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
12233 0x4b, 0xfe, 0xdb, 0x10,
12234 0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
12235 0x89, 0xf0, 0x24, 0x33,
12236 0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
12237 0x33, 0x31, 0xdf, 0xbc,
12238 0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
12239 0x17, 0xfe, 0x2c, 0x0d,
12240 0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
12241 0x12, 0x55, 0xfe, 0x28,
12242 0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
12243 0x44, 0xfe, 0x28, 0x00,
12244 0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
12245 0x0f, 0x64, 0x12, 0x2f,
12246 0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
12247 0x0a, 0xfe, 0xb4, 0x10,
12248 0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
12249 0xfe, 0x34, 0x46, 0xac,
12250 0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
12251 0x37, 0x01, 0xf5, 0x01,
12252 0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
12253 0xfe, 0x2e, 0x03, 0x08,
12254 0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
12255 0x1a, 0xfe, 0x58, 0x12,
12256 0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
12257 0xfe, 0x50, 0x0d, 0xfe,
12258 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
12259 0xfe, 0xa9, 0x10, 0x10,
12260 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
12261 0xfe, 0x13, 0x00, 0xfe,
12262 0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
12263 0x24, 0x00, 0x8c, 0xb5,
12264 0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
12265 0xfe, 0x9d, 0x41, 0xfe,
12266 0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
12267 0xb4, 0x15, 0xfe, 0x31,
12268 0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
12269 0xec, 0xd0, 0xfc, 0x44,
12270 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
12271 0x4b, 0x91, 0xfe, 0x75,
12272 0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
12273 0x0e, 0xfe, 0x44, 0x48,
12274 0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
12275 0xfe, 0x41, 0x58, 0x09,
12276 0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
12277 0x2e, 0x03, 0x09, 0x5d,
12278 0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
12279 0xce, 0x47, 0xfe, 0xad,
12280 0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
12281 0x59, 0x13, 0x9f, 0x13,
12282 0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
12283 0xe0, 0x0e, 0x0f, 0x06,
12284 0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
12285 0x3a, 0x01, 0x56, 0xfe,
12286 0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
12287 0x20, 0x4f, 0xfe, 0x05,
12288 0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
12289 0x48, 0xf4, 0x0d, 0xfe,
12290 0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
12291 0x15, 0x1a, 0x39, 0xa0,
12292 0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
12293 0x0c, 0xfe, 0x60, 0x01,
12294 0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
12295 0x06, 0x13, 0x2f, 0x12,
12296 0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
12297 0x22, 0x9f, 0xb7, 0x13,
12298 0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
12299 0xa0, 0xb4, 0xfe, 0xd9,
12300 0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
12301 0xc3, 0xfe, 0x03, 0xdc,
12302 0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
12303 0xfe, 0x00, 0xcc, 0x04,
12304 0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
12305 0xfe, 0x1c, 0x80, 0x07,
12306 0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
12307 0xfe, 0x0c, 0x90, 0xfe,
12308 0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
12309 0x0a, 0xfe, 0x3c, 0x50,
12310 0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
12311 0x16, 0x08, 0x05, 0x1b,
12312 0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
12313 0xfe, 0x2c, 0x13, 0x01,
12314 0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
12315 0x0c, 0xfe, 0x64, 0x01,
12316 0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
12317 0x80, 0x8d, 0xfe, 0x01,
12318 0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
12319 0x22, 0x20, 0xfb, 0x79,
12320 0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
12321 0x03, 0xfe, 0xae, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012322
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012323 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
12324 0xb2, 0x00, 0xfe, 0x09,
12325 0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
12326 0x45, 0x0f, 0x46, 0x52,
12327 0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
12328 0x0f, 0x44, 0x11, 0x0f,
12329 0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
12330 0x25, 0x11, 0x13, 0x20,
12331 0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
12332 0x56, 0xfe, 0xd6, 0xf0,
12333 0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
12334 0x18, 0x1c, 0x04, 0x42,
12335 0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
12336 0xf5, 0x13, 0x04, 0x01,
12337 0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
12338 0x13, 0x32, 0x07, 0x2f,
12339 0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
12340 0x41, 0x48, 0xfe, 0x45,
12341 0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
12342 0x07, 0x11, 0xac, 0x09,
12343 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
12344 0x82, 0x4e, 0xfe, 0x14,
12345 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
12346 0xfe, 0x01, 0xec, 0xa2,
12347 0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
12348 0x2a, 0x01, 0xe3, 0xfe,
12349 0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
12350 0xfe, 0x48, 0x12, 0x07,
12351 0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
12352 0xfe, 0x32, 0x12, 0x07,
12353 0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
12354 0x1f, 0xfe, 0x12, 0x12,
12355 0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
12356 0x94, 0x4b, 0x04, 0x2d,
12357 0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
12358 0x32, 0x07, 0xa6, 0xfe,
12359 0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
12360 0x5a, 0xfe, 0x72, 0x12,
12361 0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
12362 0xfe, 0x26, 0x13, 0x03,
12363 0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
12364 0x0c, 0x7f, 0x0c, 0x80,
12365 0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
12366 0x3c, 0xfe, 0x04, 0x55,
12367 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
12368 0x91, 0x10, 0x03, 0x3f,
12369 0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
12370 0x88, 0x9b, 0x2e, 0x9c,
12371 0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
12372 0x56, 0x0c, 0x5e, 0x14,
12373 0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
12374 0x03, 0x60, 0x29, 0x61,
12375 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
12376 0x50, 0xfe, 0xc6, 0x50,
12377 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
12378 0x29, 0x3e, 0xfe, 0x40,
12379 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
12380 0x2d, 0x01, 0x0b, 0x1d,
12381 0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
12382 0x72, 0x01, 0xaf, 0x1e,
12383 0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
12384 0x0a, 0x55, 0x35, 0xfe,
12385 0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
12386 0x02, 0x72, 0xfe, 0x19,
12387 0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
12388 0x1d, 0xe8, 0x33, 0x31,
12389 0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
12390 0x0b, 0x1c, 0x34, 0x1d,
12391 0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
12392 0x33, 0x31, 0xfe, 0xe8,
12393 0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
12394 0x05, 0x1f, 0x35, 0xa9,
12395 0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
12396 0x14, 0x01, 0xaf, 0x8c,
12397 0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
12398 0x03, 0x45, 0x28, 0x35,
12399 0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
12400 0x03, 0x5c, 0xc1, 0x0c,
12401 0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
12402 0x89, 0x01, 0x0b, 0x1c,
12403 0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
12404 0xfe, 0x42, 0x58, 0xf1,
12405 0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
12406 0xf4, 0x06, 0xea, 0x32,
12407 0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
12408 0x01, 0x0b, 0x26, 0x89,
12409 0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
12410 0x26, 0xfe, 0xd4, 0x13,
12411 0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
12412 0x13, 0x1c, 0xfe, 0xd0,
12413 0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
12414 0x0f, 0x71, 0xff, 0x02,
12415 0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
12416 0x00, 0x5c, 0x04, 0x0f,
12417 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
12418 0xfe, 0x00, 0x5c, 0x04,
12419 0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
12420 0x02, 0x00, 0x57, 0x52,
12421 0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
12422 0x87, 0x04, 0xfe, 0x03,
12423 0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
12424 0xfe, 0x00, 0x7d, 0xfe,
12425 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
12426 0x14, 0x5f, 0x57, 0x3f,
12427 0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
12428 0x5a, 0x8d, 0x04, 0x01,
12429 0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
12430 0xfe, 0x96, 0x15, 0x33,
12431 0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
12432 0x0a, 0xfe, 0xc1, 0x59,
12433 0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
12434 0x21, 0x69, 0x1a, 0xee,
12435 0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
12436 0x30, 0xfe, 0x78, 0x10,
12437 0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
12438 0x98, 0xfe, 0x30, 0x00,
12439 0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
12440 0x98, 0xfe, 0x64, 0x00,
12441 0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
12442 0x10, 0x69, 0x06, 0xfe,
12443 0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
12444 0x18, 0x59, 0x0f, 0x06,
12445 0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
12446 0x43, 0xf4, 0x9f, 0xfe,
12447 0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
12448 0x9e, 0xfe, 0xf3, 0x10,
12449 0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
12450 0x17, 0xfe, 0x4d, 0xe4,
12451 0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
12452 0x17, 0xfe, 0x4d, 0xe4,
12453 0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
12454 0xf4, 0x00, 0xe9, 0x91,
12455 0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
12456 0x04, 0x16, 0x06, 0x01,
12457 0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
12458 0x0b, 0x26, 0xf3, 0x76,
12459 0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
12460 0x16, 0x19, 0x01, 0x0b,
12461 0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
12462 0x0b, 0x26, 0xb1, 0x76,
12463 0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
12464 0xfe, 0x48, 0x13, 0xb8,
12465 0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
12466 0xec, 0xfe, 0x27, 0x01,
12467 0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
12468 0x07, 0xfe, 0xe3, 0x00,
12469 0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
12470 0x22, 0xd4, 0x07, 0x06,
12471 0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
12472 0x07, 0x11, 0xae, 0x09,
12473 0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
12474 0x0e, 0x8e, 0xfe, 0x80,
12475 0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
12476 0x09, 0x48, 0x01, 0x0e,
12477 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
12478 0x80, 0xfe, 0x80, 0x4c,
12479 0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
12480 0x09, 0x5d, 0x01, 0x87,
12481 0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
12482 0x19, 0xde, 0xfe, 0x24,
12483 0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
12484 0x17, 0xad, 0x9a, 0x1b,
12485 0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
12486 0x16, 0xfe, 0xda, 0x10,
12487 0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
12488 0x18, 0x58, 0x03, 0xfe,
12489 0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
12490 0xf4, 0x06, 0xfe, 0x3c,
12491 0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
12492 0x97, 0xfe, 0x38, 0x17,
12493 0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
12494 0x10, 0x18, 0x11, 0x75,
12495 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
12496 0x2e, 0x97, 0xfe, 0x5a,
12497 0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
12498 0xfe, 0x98, 0xe7, 0x00,
12499 0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
12500 0xfe, 0x30, 0xbc, 0xfe,
12501 0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
12502 0xcb, 0x97, 0xfe, 0x92,
12503 0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
12504 0x42, 0x10, 0xfe, 0x02,
12505 0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
12506 0x03, 0xa1, 0xfe, 0x1d,
12507 0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
12508 0x9a, 0x5b, 0x41, 0xfe,
12509 0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
12510 0x11, 0x12, 0xfe, 0xdd,
12511 0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
12512 0x17, 0x15, 0x06, 0x39,
12513 0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
12514 0xfe, 0x7e, 0x18, 0x1e,
12515 0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
12516 0x12, 0xfe, 0xe1, 0x10,
12517 0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
12518 0x13, 0x42, 0x92, 0x09,
12519 0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
12520 0xf0, 0xfe, 0x00, 0xcc,
12521 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
12522 0x0e, 0xfe, 0x80, 0x4c,
12523 0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
12524 0x24, 0x12, 0xfe, 0x14,
12525 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
12526 0xe7, 0x0a, 0x10, 0xfe,
12527 0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
12528 0x08, 0x54, 0x1b, 0x37,
12529 0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
12530 0x90, 0x3a, 0xce, 0x3b,
12531 0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
12532 0x13, 0xa3, 0x04, 0x09,
12533 0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
12534 0x44, 0x17, 0xfe, 0xe8,
12535 0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
12536 0x5d, 0x01, 0xa8, 0x09,
12537 0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
12538 0x1c, 0x19, 0x03, 0xfe,
12539 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
12540 0x6b, 0xfe, 0x2e, 0x19,
12541 0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
12542 0xfe, 0x0b, 0x00, 0x6b,
12543 0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
12544 0x08, 0x10, 0x03, 0xfe,
12545 0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
12546 0x04, 0x68, 0x54, 0xe7,
12547 0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
12548 0x1a, 0xf4, 0xfe, 0x00,
12549 0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
12550 0x04, 0x07, 0x7e, 0xfe,
12551 0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
12552 0x07, 0x1a, 0xfe, 0x5a,
12553 0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
12554 0x25, 0x6d, 0xe5, 0x07,
12555 0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
12556 0xa9, 0xb8, 0x04, 0x15,
12557 0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
12558 0x40, 0x5c, 0x04, 0x1c,
12559 0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
12560 0xf7, 0xfe, 0x82, 0xf0,
12561 0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070012562};
12563
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012564static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
12565static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012566
12567/* Microcode buffer is kept after initialization for error recovery. */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040012568static unsigned char _adv_asc38C1600_buf[] = {
12569 0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
12570 0x18, 0xe4, 0x01, 0x00,
12571 0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
12572 0x07, 0x17, 0xc0, 0x5f,
12573 0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
12574 0x85, 0xf0, 0x86, 0xf0,
12575 0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
12576 0x98, 0x57, 0x01, 0xe6,
12577 0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
12578 0x38, 0x54, 0x32, 0xf0,
12579 0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
12580 0x00, 0xe6, 0xb1, 0xf0,
12581 0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
12582 0x06, 0x13, 0x0c, 0x1c,
12583 0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
12584 0xb9, 0x54, 0x00, 0x80,
12585 0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
12586 0x03, 0xe6, 0x01, 0xea,
12587 0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
12588 0x04, 0x13, 0xbb, 0x55,
12589 0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
12590 0xbb, 0x00, 0xc0, 0x00,
12591 0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
12592 0x4c, 0x1c, 0x4e, 0x1c,
12593 0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
12594 0x24, 0x01, 0x3c, 0x01,
12595 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
12596 0x78, 0x01, 0x7c, 0x01,
12597 0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
12598 0x6e, 0x1e, 0x02, 0x48,
12599 0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
12600 0x03, 0xfc, 0x06, 0x00,
12601 0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
12602 0x30, 0x1c, 0x38, 0x1c,
12603 0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
12604 0x5d, 0xf0, 0xa7, 0xf0,
12605 0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
12606 0x33, 0x00, 0x34, 0x00,
12607 0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
12608 0x79, 0x01, 0x3c, 0x09,
12609 0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
12610 0x40, 0x16, 0x50, 0x16,
12611 0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
12612 0x05, 0xf0, 0x09, 0xf0,
12613 0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
12614 0x9c, 0x00, 0xa4, 0x00,
12615 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
12616 0xe9, 0x09, 0x5c, 0x0c,
12617 0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
12618 0x42, 0x1d, 0x08, 0x44,
12619 0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
12620 0x83, 0x55, 0x83, 0x59,
12621 0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
12622 0x4b, 0xf4, 0x04, 0xf8,
12623 0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
12624 0xa8, 0x00, 0xaa, 0x00,
12625 0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
12626 0x7a, 0x01, 0x82, 0x01,
12627 0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
12628 0x68, 0x08, 0x10, 0x0d,
12629 0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
12630 0xf3, 0x10, 0x06, 0x12,
12631 0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
12632 0xf0, 0x35, 0x05, 0xfe,
12633 0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
12634 0xfe, 0x88, 0x01, 0xff,
12635 0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
12636 0x00, 0xfe, 0x57, 0x24,
12637 0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
12638 0x00, 0x00, 0xff, 0x08,
12639 0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
12640 0xff, 0xff, 0xff, 0x13,
12641 0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
12642 0xfe, 0x04, 0xf7, 0xe8,
12643 0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
12644 0x0d, 0x51, 0x37, 0xfe,
12645 0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
12646 0xfe, 0xf8, 0x01, 0xfe,
12647 0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
12648 0x05, 0xfe, 0x08, 0x0f,
12649 0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
12650 0x28, 0x1c, 0x03, 0xfe,
12651 0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
12652 0x48, 0xf0, 0xfe, 0x90,
12653 0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
12654 0x02, 0xfe, 0x46, 0xf0,
12655 0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
12656 0xfe, 0x4e, 0x02, 0xfe,
12657 0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
12658 0x0d, 0xa2, 0x1c, 0x07,
12659 0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
12660 0x1c, 0xf5, 0xfe, 0x1e,
12661 0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
12662 0xde, 0x0a, 0x81, 0x01,
12663 0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
12664 0x81, 0x01, 0x5c, 0xfe,
12665 0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
12666 0xfe, 0x58, 0x1c, 0x1c,
12667 0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
12668 0x2b, 0xfe, 0x9e, 0x02,
12669 0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
12670 0x00, 0x47, 0xb8, 0x01,
12671 0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
12672 0x1a, 0x31, 0xfe, 0x69,
12673 0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
12674 0x1e, 0x1e, 0x20, 0x2c,
12675 0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
12676 0x44, 0x15, 0x56, 0x51,
12677 0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
12678 0x01, 0x18, 0x09, 0x00,
12679 0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
12680 0x18, 0xfe, 0xc8, 0x54,
12681 0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
12682 0xfe, 0x02, 0xe8, 0x30,
12683 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
12684 0xfe, 0xe4, 0x01, 0xfe,
12685 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
12686 0x26, 0xf0, 0xfe, 0x66,
12687 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
12688 0xef, 0x10, 0xfe, 0x9f,
12689 0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
12690 0x70, 0x37, 0xfe, 0x48,
12691 0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
12692 0x21, 0xb9, 0xc7, 0x20,
12693 0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
12694 0xe1, 0x2a, 0xeb, 0xfe,
12695 0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
12696 0x15, 0xfe, 0xe4, 0x00,
12697 0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
12698 0xfe, 0x06, 0xf0, 0xfe,
12699 0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
12700 0x03, 0x81, 0x1e, 0x1b,
12701 0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
12702 0xea, 0xfe, 0x46, 0x1c,
12703 0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
12704 0xfe, 0x48, 0x1c, 0x75,
12705 0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
12706 0xe1, 0x01, 0x18, 0x77,
12707 0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
12708 0x8f, 0xfe, 0x70, 0x02,
12709 0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
12710 0x16, 0xfe, 0x4a, 0x04,
12711 0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
12712 0x02, 0x00, 0x10, 0x01,
12713 0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
12714 0xee, 0xfe, 0x4c, 0x44,
12715 0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
12716 0x7b, 0xec, 0x60, 0x8d,
12717 0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
12718 0x0c, 0x06, 0x28, 0xfe,
12719 0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
12720 0x13, 0x34, 0xfe, 0x4c,
12721 0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
12722 0x13, 0x01, 0x0c, 0x06,
12723 0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
12724 0x28, 0xf9, 0x1f, 0x7f,
12725 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
12726 0xfe, 0xa4, 0x0e, 0x05,
12727 0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
12728 0x9c, 0x93, 0x3a, 0x0b,
12729 0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
12730 0x7d, 0x1d, 0xfe, 0x46,
12731 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
12732 0xfe, 0x87, 0x83, 0xfe,
12733 0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
12734 0x13, 0x0f, 0xfe, 0x20,
12735 0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
12736 0x12, 0x01, 0x38, 0x06,
12737 0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
12738 0x05, 0xd0, 0x54, 0x01,
12739 0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
12740 0x50, 0x12, 0x5e, 0xff,
12741 0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
12742 0x00, 0x10, 0x2f, 0xfe,
12743 0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
12744 0x38, 0xfe, 0x4a, 0xf0,
12745 0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
12746 0x21, 0x00, 0xf1, 0x2e,
12747 0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
12748 0x10, 0x2f, 0xfe, 0xd0,
12749 0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
12750 0x1c, 0x00, 0x4d, 0x01,
12751 0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
12752 0x28, 0xfe, 0x24, 0x12,
12753 0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
12754 0x0d, 0x00, 0x01, 0x42,
12755 0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
12756 0x03, 0xb6, 0x1e, 0xfe,
12757 0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
12758 0xfe, 0x72, 0x06, 0x0a,
12759 0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
12760 0x19, 0x16, 0xfe, 0x68,
12761 0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
12762 0x03, 0x9a, 0x1e, 0xfe,
12763 0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
12764 0x48, 0xfe, 0x92, 0x06,
12765 0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
12766 0x58, 0xff, 0x02, 0x00,
12767 0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
12768 0xfe, 0xea, 0x06, 0x01,
12769 0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
12770 0xfe, 0xe0, 0x06, 0x15,
12771 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
12772 0x01, 0x84, 0xfe, 0xae,
12773 0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
12774 0x1e, 0xfe, 0x1a, 0x12,
12775 0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
12776 0x43, 0x48, 0x62, 0x80,
12777 0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
12778 0x36, 0xfe, 0x02, 0xf6,
12779 0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
12780 0xd0, 0x0d, 0x17, 0xfe,
12781 0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
12782 0x9e, 0x15, 0x82, 0x01,
12783 0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
12784 0x57, 0x10, 0xe6, 0x05,
12785 0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
12786 0xfe, 0x9c, 0x32, 0x5f,
12787 0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
12788 0xfe, 0x0a, 0xf0, 0xfe,
12789 0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
12790 0xaf, 0xa0, 0x05, 0x29,
12791 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
12792 0x00, 0x01, 0x08, 0x14,
12793 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
12794 0x14, 0x00, 0x05, 0xfe,
12795 0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
12796 0x12, 0xfe, 0x30, 0x13,
12797 0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
12798 0x01, 0x08, 0x14, 0x00,
12799 0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
12800 0x78, 0x4f, 0x0f, 0xfe,
12801 0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
12802 0x28, 0x48, 0xfe, 0x6c,
12803 0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
12804 0x12, 0x53, 0x63, 0x4e,
12805 0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
12806 0x6c, 0x08, 0xaf, 0xa0,
12807 0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
12808 0x05, 0xed, 0xfe, 0x9c,
12809 0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
12810 0x1e, 0xfe, 0x99, 0x58,
12811 0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
12812 0x22, 0x6b, 0x01, 0x0c,
12813 0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
12814 0x1e, 0x47, 0x2c, 0x7a,
12815 0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
12816 0x01, 0x0c, 0x61, 0x65,
12817 0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
12818 0x16, 0xfe, 0x08, 0x50,
12819 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
12820 0x01, 0xfe, 0xce, 0x1e,
12821 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
12822 0x01, 0xfe, 0xfe, 0x1e,
12823 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
12824 0x10, 0x01, 0x0c, 0x06,
12825 0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
12826 0x10, 0x6a, 0x22, 0x6b,
12827 0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
12828 0xfe, 0x9f, 0x83, 0x33,
12829 0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
12830 0x3a, 0x0b, 0xfe, 0xc6,
12831 0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
12832 0x01, 0xfe, 0xce, 0x1e,
12833 0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
12834 0x04, 0xfe, 0xc0, 0x93,
12835 0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
12836 0x10, 0x4b, 0x22, 0x4c,
12837 0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
12838 0x4e, 0x11, 0x2f, 0xfe,
12839 0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
12840 0x3c, 0x37, 0x88, 0xf5,
12841 0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
12842 0xd3, 0xfe, 0x42, 0x0a,
12843 0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
12844 0x05, 0x29, 0x01, 0x41,
12845 0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
12846 0xfe, 0x14, 0x12, 0x01,
12847 0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
12848 0x2e, 0x1c, 0x05, 0xfe,
12849 0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
12850 0xfe, 0x2c, 0x1c, 0xfe,
12851 0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
12852 0x92, 0x10, 0xc4, 0xf6,
12853 0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
12854 0xe7, 0x10, 0xfe, 0x2b,
12855 0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
12856 0xac, 0xfe, 0xd2, 0xf0,
12857 0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
12858 0x1b, 0xbf, 0xd4, 0x5b,
12859 0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
12860 0x5e, 0x32, 0x1f, 0x7f,
12861 0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
12862 0x05, 0x70, 0xfe, 0x74,
12863 0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
12864 0x0f, 0x4d, 0x01, 0xfe,
12865 0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
12866 0x0d, 0x2b, 0xfe, 0xe2,
12867 0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
12868 0xfe, 0x88, 0x13, 0x21,
12869 0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
12870 0x83, 0x83, 0xfe, 0xc9,
12871 0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
12872 0x91, 0x04, 0xfe, 0x84,
12873 0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
12874 0xfe, 0xcb, 0x57, 0x0b,
12875 0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
12876 0x6a, 0x3b, 0x6b, 0x10,
12877 0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
12878 0x20, 0x6e, 0xdb, 0x64,
12879 0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
12880 0xfe, 0x04, 0xfa, 0x64,
12881 0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
12882 0x10, 0x98, 0x91, 0x6c,
12883 0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
12884 0x4b, 0x7e, 0x4c, 0x01,
12885 0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
12886 0x58, 0xfe, 0x91, 0x58,
12887 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
12888 0x1b, 0x40, 0x01, 0x0c,
12889 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
12890 0xfe, 0x10, 0x90, 0x04,
12891 0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
12892 0x79, 0x0b, 0x0e, 0xfe,
12893 0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
12894 0x01, 0x0c, 0x06, 0x0d,
12895 0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
12896 0x0c, 0x58, 0xfe, 0x8d,
12897 0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
12898 0x83, 0x33, 0x0b, 0x0e,
12899 0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
12900 0x19, 0xfe, 0x19, 0x41,
12901 0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
12902 0x19, 0xfe, 0x44, 0x00,
12903 0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
12904 0x4c, 0xfe, 0x0c, 0x51,
12905 0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
12906 0x76, 0x10, 0xac, 0xfe,
12907 0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
12908 0xe3, 0x23, 0x07, 0xfe,
12909 0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
12910 0xcc, 0x0c, 0x1f, 0x92,
12911 0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
12912 0x0c, 0xfe, 0x3e, 0x10,
12913 0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
12914 0xfe, 0xcb, 0xf0, 0xfe,
12915 0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
12916 0xf4, 0x0c, 0x19, 0x94,
12917 0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
12918 0xfe, 0xcc, 0xf0, 0xef,
12919 0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
12920 0x4e, 0x11, 0x2f, 0xfe,
12921 0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
12922 0x3c, 0x37, 0x88, 0xf5,
12923 0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
12924 0x2f, 0xfe, 0x3e, 0x0d,
12925 0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
12926 0xd2, 0x9f, 0xd3, 0x9f,
12927 0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
12928 0xc5, 0x75, 0xd7, 0x99,
12929 0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
12930 0x9c, 0x2f, 0xfe, 0x8c,
12931 0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
12932 0x42, 0x00, 0x05, 0x70,
12933 0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
12934 0x0d, 0xfe, 0x44, 0x13,
12935 0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
12936 0xfe, 0xda, 0x0e, 0x0a,
12937 0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
12938 0x10, 0x01, 0xfe, 0xf4,
12939 0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
12940 0x15, 0x56, 0x01, 0x85,
12941 0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
12942 0xcc, 0x10, 0x01, 0xa7,
12943 0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
12944 0xfe, 0x99, 0x83, 0xfe,
12945 0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
12946 0x43, 0x00, 0xfe, 0xa2,
12947 0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
12948 0x00, 0x1d, 0x40, 0x15,
12949 0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
12950 0xfe, 0x3a, 0x03, 0x01,
12951 0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
12952 0x76, 0x06, 0x12, 0xfe,
12953 0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
12954 0xfe, 0x9d, 0xf0, 0xfe,
12955 0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
12956 0x0c, 0x61, 0x12, 0x44,
12957 0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
12958 0xfe, 0x2e, 0x10, 0x19,
12959 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
12960 0xfe, 0x41, 0x00, 0xa2,
12961 0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
12962 0xea, 0x4f, 0xfe, 0x04,
12963 0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
12964 0x35, 0xfe, 0x12, 0x1c,
12965 0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
12966 0xfe, 0xd4, 0x11, 0x05,
12967 0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
12968 0xce, 0x45, 0x31, 0x51,
12969 0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
12970 0x67, 0xfe, 0x98, 0x56,
12971 0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
12972 0x0c, 0x06, 0x28, 0xfe,
12973 0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
12974 0xfe, 0xfa, 0x14, 0xfe,
12975 0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
12976 0xfe, 0xe0, 0x14, 0xfe,
12977 0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
12978 0xfe, 0xad, 0x13, 0x05,
12979 0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
12980 0xe7, 0xfe, 0x08, 0x1c,
12981 0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
12982 0x48, 0x55, 0xa5, 0x3b,
12983 0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
12984 0xf0, 0x1a, 0x03, 0xfe,
12985 0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
12986 0xec, 0xe7, 0x53, 0x00,
12987 0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
12988 0x01, 0xfe, 0x62, 0x1b,
12989 0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
12990 0xea, 0xe7, 0x53, 0x92,
12991 0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
12992 0xfe, 0x38, 0x01, 0x23,
12993 0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
12994 0x01, 0x01, 0xfe, 0x1e,
12995 0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
12996 0x26, 0x02, 0x21, 0x96,
12997 0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
12998 0xc3, 0xfe, 0xe1, 0x10,
12999 0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
13000 0xfe, 0x03, 0xdc, 0xfe,
13001 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
13002 0x00, 0xcc, 0x02, 0xfe,
13003 0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
13004 0x0f, 0xfe, 0x1c, 0x80,
13005 0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
13006 0x0f, 0xfe, 0x1e, 0x80,
13007 0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
13008 0x1d, 0x80, 0x04, 0xfe,
13009 0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
13010 0x1e, 0xac, 0xfe, 0x14,
13011 0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
13012 0x1f, 0xfe, 0x30, 0xf4,
13013 0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
13014 0x56, 0xfb, 0x01, 0xfe,
13015 0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
13016 0xfe, 0x00, 0x1d, 0x15,
13017 0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
13018 0x22, 0x1b, 0xfe, 0x1e,
13019 0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
13020 0x96, 0x90, 0x04, 0xfe,
13021 0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
13022 0x01, 0x01, 0x0c, 0x06,
13023 0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
13024 0x0e, 0x77, 0xfe, 0x01,
13025 0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
13026 0x21, 0x2c, 0xfe, 0x00,
13027 0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
13028 0x06, 0x58, 0x03, 0xfe,
13029 0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
13030 0x03, 0xfe, 0xb2, 0x00,
13031 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
13032 0x66, 0x10, 0x55, 0x10,
13033 0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
13034 0x54, 0x2b, 0xfe, 0x88,
13035 0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
13036 0x91, 0x54, 0x2b, 0xfe,
13037 0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
13038 0x00, 0x40, 0x8d, 0x2c,
13039 0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
13040 0x12, 0x1c, 0x75, 0xfe,
13041 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
13042 0x14, 0xfe, 0x0e, 0x47,
13043 0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
13044 0xa7, 0x90, 0x34, 0x60,
13045 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
13046 0x09, 0x56, 0xfe, 0x34,
13047 0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
13048 0xfe, 0x45, 0x48, 0x01,
13049 0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
13050 0x09, 0x1a, 0xa5, 0x0a,
13051 0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
13052 0xfe, 0x14, 0x56, 0xfe,
13053 0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
13054 0xec, 0xb8, 0xfe, 0x9e,
13055 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
13056 0xf4, 0xfe, 0xdd, 0x10,
13057 0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
13058 0x12, 0x09, 0x0d, 0xfe,
13059 0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
13060 0x13, 0x09, 0xfe, 0x23,
13061 0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
13062 0x24, 0xfe, 0x12, 0x12,
13063 0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
13064 0xae, 0x41, 0x02, 0x32,
13065 0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
13066 0x35, 0x32, 0x01, 0x43,
13067 0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
13068 0x13, 0x01, 0x0c, 0x06,
13069 0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
13070 0xe5, 0x55, 0xb0, 0xfe,
13071 0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
13072 0xfe, 0xb6, 0x0e, 0x10,
13073 0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
13074 0x88, 0x20, 0x6e, 0x01,
13075 0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
13076 0x55, 0xfe, 0x04, 0xfa,
13077 0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
13078 0xfe, 0x40, 0x56, 0xfe,
13079 0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
13080 0x44, 0x55, 0xfe, 0xe5,
13081 0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
13082 0x68, 0x22, 0x69, 0x01,
13083 0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
13084 0x6b, 0xfe, 0x2c, 0x50,
13085 0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
13086 0x50, 0x03, 0x68, 0x3b,
13087 0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
13088 0x40, 0x50, 0xfe, 0xc2,
13089 0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
13090 0x16, 0x3d, 0x27, 0x25,
13091 0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
13092 0xa6, 0x23, 0x3f, 0x1b,
13093 0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
13094 0xfe, 0x0a, 0x55, 0x31,
13095 0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
13096 0x51, 0x05, 0x72, 0x01,
13097 0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
13098 0x2a, 0x3c, 0x16, 0xc0,
13099 0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
13100 0xfe, 0x66, 0x15, 0x05,
13101 0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
13102 0x2b, 0x3d, 0x01, 0x08,
13103 0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
13104 0xb6, 0x1e, 0x83, 0x01,
13105 0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
13106 0x07, 0x90, 0x3f, 0x01,
13107 0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
13108 0x01, 0x43, 0x09, 0x82,
13109 0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
13110 0x05, 0x72, 0xfe, 0xc0,
13111 0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
13112 0x32, 0x01, 0x08, 0x17,
13113 0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
13114 0x3d, 0x27, 0x25, 0xbd,
13115 0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
13116 0xe8, 0x14, 0x01, 0xa6,
13117 0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
13118 0x0e, 0x12, 0x01, 0x43,
13119 0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
13120 0x01, 0x08, 0x17, 0x73,
13121 0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
13122 0x27, 0x25, 0xbd, 0x09,
13123 0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
13124 0xb6, 0x14, 0x86, 0xa8,
13125 0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
13126 0x82, 0x4e, 0x05, 0x72,
13127 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
13128 0xfe, 0xc0, 0x19, 0x05,
13129 0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
13130 0xcc, 0x01, 0x08, 0x26,
13131 0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
13132 0xcc, 0x15, 0x5e, 0x32,
13133 0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
13134 0xad, 0x23, 0xfe, 0xff,
13135 0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
13136 0x00, 0x57, 0x52, 0xad,
13137 0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
13138 0x02, 0x00, 0x57, 0x52,
13139 0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
13140 0x02, 0x13, 0x58, 0xff,
13141 0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
13142 0x5c, 0x0a, 0x55, 0x01,
13143 0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
13144 0xff, 0x03, 0x00, 0x54,
13145 0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
13146 0x7c, 0x3a, 0x0b, 0x0e,
13147 0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
13148 0xfe, 0x1a, 0xf7, 0x00,
13149 0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
13150 0xda, 0x6d, 0x02, 0xfe,
13151 0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
13152 0x02, 0x01, 0xc6, 0xfe,
13153 0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
13154 0x25, 0xbe, 0x01, 0x08,
13155 0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
13156 0x03, 0x9a, 0x1e, 0xfe,
13157 0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
13158 0x48, 0xfe, 0x08, 0x17,
13159 0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
13160 0x17, 0x4d, 0x13, 0x07,
13161 0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
13162 0xff, 0x02, 0x83, 0x55,
13163 0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
13164 0x17, 0x1c, 0x63, 0x13,
13165 0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
13166 0x00, 0xb0, 0xfe, 0x80,
13167 0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
13168 0x53, 0x07, 0xfe, 0x60,
13169 0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
13170 0x00, 0x1c, 0x95, 0x13,
13171 0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
13172 0xfe, 0x43, 0xf4, 0x96,
13173 0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
13174 0xf4, 0x94, 0xf6, 0x8b,
13175 0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
13176 0xda, 0x17, 0x62, 0x49,
13177 0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
13178 0x71, 0x50, 0x26, 0xfe,
13179 0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
13180 0x58, 0x02, 0x50, 0x13,
13181 0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
13182 0x25, 0xbe, 0xfe, 0x03,
13183 0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
13184 0x0a, 0x01, 0x08, 0x16,
13185 0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
13186 0x01, 0x08, 0x16, 0xa9,
13187 0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
13188 0x08, 0x16, 0xa9, 0x27,
13189 0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
13190 0x01, 0x38, 0x06, 0x24,
13191 0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
13192 0x78, 0x03, 0x9a, 0x1e,
13193 0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
13194 0xfe, 0x40, 0x5a, 0x23,
13195 0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
13196 0x80, 0x48, 0xfe, 0xaa,
13197 0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
13198 0xfe, 0xac, 0x1d, 0xfe,
13199 0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
13200 0x43, 0x48, 0x2d, 0x93,
13201 0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
13202 0x36, 0xfe, 0x34, 0xf4,
13203 0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
13204 0x28, 0x10, 0xfe, 0xc0,
13205 0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
13206 0x18, 0x45, 0xfe, 0x1c,
13207 0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
13208 0x19, 0xfe, 0x04, 0xf4,
13209 0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
13210 0x21, 0xfe, 0x7f, 0x01,
13211 0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
13212 0x7e, 0x01, 0xfe, 0xc8,
13213 0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
13214 0x21, 0xfe, 0x81, 0x01,
13215 0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
13216 0x13, 0x0d, 0x02, 0x14,
13217 0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
13218 0xfe, 0x82, 0x19, 0x14,
13219 0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
13220 0x08, 0x02, 0x14, 0x07,
13221 0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
13222 0x01, 0x08, 0x17, 0xc1,
13223 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
13224 0x08, 0x02, 0x50, 0x02,
13225 0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
13226 0x14, 0x12, 0x01, 0x08,
13227 0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
13228 0x08, 0x17, 0x74, 0xfe,
13229 0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
13230 0x74, 0x5f, 0xcc, 0x01,
13231 0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
13232 0xfe, 0x49, 0xf4, 0x00,
13233 0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
13234 0x02, 0x00, 0x10, 0x2f,
13235 0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
13236 0x16, 0xfe, 0x64, 0x1a,
13237 0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
13238 0x61, 0x07, 0x44, 0x02,
13239 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
13240 0x13, 0x0a, 0x9d, 0x01,
13241 0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
13242 0xfe, 0x80, 0xe7, 0x1a,
13243 0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
13244 0x0a, 0x5a, 0x01, 0x18,
13245 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
13246 0x7e, 0x1e, 0xfe, 0x80,
13247 0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
13248 0xfe, 0x80, 0x4c, 0x0a,
13249 0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
13250 0xfe, 0x19, 0xde, 0xfe,
13251 0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
13252 0x2a, 0x1c, 0xfa, 0xb3,
13253 0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
13254 0xf4, 0x1a, 0xfe, 0xfa,
13255 0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
13256 0xfe, 0x18, 0x58, 0x03,
13257 0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
13258 0xfe, 0x30, 0xf4, 0x07,
13259 0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
13260 0xf7, 0x24, 0xb1, 0xfe,
13261 0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
13262 0xfe, 0xba, 0x10, 0x1c,
13263 0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
13264 0x1d, 0xf7, 0x54, 0xb1,
13265 0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
13266 0xaf, 0x19, 0xfe, 0x98,
13267 0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
13268 0x1a, 0x87, 0x8b, 0x0f,
13269 0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
13270 0xfe, 0x32, 0x90, 0x04,
13271 0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
13272 0x7c, 0x12, 0xfe, 0x0f,
13273 0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
13274 0x31, 0x02, 0xc9, 0x2b,
13275 0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
13276 0x6a, 0xfe, 0x19, 0xfe,
13277 0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
13278 0x1b, 0xfe, 0x36, 0x14,
13279 0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
13280 0xfe, 0x80, 0xe7, 0x1a,
13281 0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
13282 0x30, 0xfe, 0x12, 0x45,
13283 0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
13284 0x39, 0xf0, 0x75, 0x26,
13285 0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
13286 0xe3, 0x23, 0x07, 0xfe,
13287 0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
13288 0x56, 0xfe, 0x3c, 0x13,
13289 0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
13290 0x01, 0x18, 0xcb, 0xfe,
13291 0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
13292 0xfe, 0x00, 0xcc, 0xcb,
13293 0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
13294 0xfe, 0x80, 0x4c, 0x01,
13295 0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
13296 0x12, 0xfe, 0x14, 0x56,
13297 0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
13298 0x0d, 0x19, 0xfe, 0x15,
13299 0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
13300 0x83, 0xfe, 0x18, 0x80,
13301 0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
13302 0x90, 0xfe, 0xba, 0x90,
13303 0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
13304 0x21, 0xb9, 0x88, 0x20,
13305 0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
13306 0x18, 0xfe, 0x49, 0x44,
13307 0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
13308 0x1a, 0xa4, 0x0a, 0x67,
13309 0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
13310 0x1d, 0x7b, 0xfe, 0x52,
13311 0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
13312 0x4e, 0xe4, 0xdd, 0x7b,
13313 0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
13314 0xfe, 0x4e, 0xe4, 0xfe,
13315 0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
13316 0xfe, 0x08, 0x10, 0x03,
13317 0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
13318 0x68, 0x54, 0xfe, 0xf1,
13319 0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
13320 0xfe, 0x1a, 0xf4, 0xfe,
13321 0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
13322 0x09, 0x92, 0xfe, 0x5a,
13323 0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
13324 0x5a, 0xf0, 0xfe, 0xc8,
13325 0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
13326 0x1a, 0x10, 0x09, 0x0d,
13327 0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
13328 0x1f, 0x93, 0x01, 0x42,
13329 0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
13330 0xfe, 0x14, 0xf0, 0x08,
13331 0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
13332 0xfe, 0x82, 0xf0, 0xfe,
13333 0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
13334 0x02, 0x0f, 0xfe, 0x18,
13335 0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
13336 0x80, 0x04, 0xfe, 0x82,
13337 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
13338 0x83, 0x33, 0x0b, 0x0e,
13339 0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
13340 0x02, 0x0f, 0xfe, 0x04,
13341 0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
13342 0x80, 0x04, 0xfe, 0x80,
13343 0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
13344 0xfe, 0x99, 0x83, 0xfe,
13345 0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
13346 0x83, 0xfe, 0xce, 0x47,
13347 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
13348 0x0b, 0x0e, 0x02, 0x0f,
13349 0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13350 0xfe, 0x08, 0x90, 0x04,
13351 0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
13352 0xfe, 0x8a, 0x93, 0x79,
13353 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
13354 0x0b, 0x0e, 0x02, 0x0f,
13355 0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
13356 0xfe, 0x3c, 0x90, 0x04,
13357 0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
13358 0x04, 0xfe, 0x83, 0x83,
13359 0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -070013360};
13361
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013362static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf); /* 0x1673 */
13363static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL; /* Expanded little-endian checksum. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013364
13365/* a_init.c */
13366/*
13367 * EEPROM Configuration.
13368 *
13369 * All drivers should use this structure to set the default EEPROM
13370 * configuration. The BIOS now uses this structure when it is built.
13371 * Additional structure information can be found in a_condor.h where
13372 * the structure is defined.
13373 *
13374 * The *_Field_IsChar structs are needed to correct for endianness.
13375 * These values are read from the board 16 bits at a time directly
13376 * into the structs. Because some fields are char, the values will be
13377 * in the wrong order. The *_Field_IsChar tells when to flip the
13378 * bytes. Data read and written to PCI memory is automatically swapped
13379 * on big-endian platforms so char fields read as words are actually being
13380 * unswapped on big-endian platforms.
13381 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013382static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013383 ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */
13384 0x0000, /* cfg_msw */
13385 0xFFFF, /* disc_enable */
13386 0xFFFF, /* wdtr_able */
13387 0xFFFF, /* sdtr_able */
13388 0xFFFF, /* start_motor */
13389 0xFFFF, /* tagqng_able */
13390 0xFFFF, /* bios_scan */
13391 0, /* scam_tolerant */
13392 7, /* adapter_scsi_id */
13393 0, /* bios_boot_delay */
13394 3, /* scsi_reset_delay */
13395 0, /* bios_id_lun */
13396 0, /* termination */
13397 0, /* reserved1 */
13398 0xFFE7, /* bios_ctrl */
13399 0xFFFF, /* ultra_able */
13400 0, /* reserved2 */
13401 ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
13402 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13403 0, /* dvc_cntl */
13404 0, /* bug_fix */
13405 0, /* serial_number_word1 */
13406 0, /* serial_number_word2 */
13407 0, /* serial_number_word3 */
13408 0, /* check_sum */
13409 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13410 , /* oem_name[16] */
13411 0, /* dvc_err_code */
13412 0, /* adv_err_code */
13413 0, /* adv_err_addr */
13414 0, /* saved_dvc_err_code */
13415 0, /* saved_adv_err_code */
13416 0, /* saved_adv_err_addr */
13417 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013418};
13419
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013420static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013421 0, /* cfg_lsw */
13422 0, /* cfg_msw */
13423 0, /* -disc_enable */
13424 0, /* wdtr_able */
13425 0, /* sdtr_able */
13426 0, /* start_motor */
13427 0, /* tagqng_able */
13428 0, /* bios_scan */
13429 0, /* scam_tolerant */
13430 1, /* adapter_scsi_id */
13431 1, /* bios_boot_delay */
13432 1, /* scsi_reset_delay */
13433 1, /* bios_id_lun */
13434 1, /* termination */
13435 1, /* reserved1 */
13436 0, /* bios_ctrl */
13437 0, /* ultra_able */
13438 0, /* reserved2 */
13439 1, /* max_host_qng */
13440 1, /* max_dvc_qng */
13441 0, /* dvc_cntl */
13442 0, /* bug_fix */
13443 0, /* serial_number_word1 */
13444 0, /* serial_number_word2 */
13445 0, /* serial_number_word3 */
13446 0, /* check_sum */
13447 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13448 , /* oem_name[16] */
13449 0, /* dvc_err_code */
13450 0, /* adv_err_code */
13451 0, /* adv_err_addr */
13452 0, /* saved_dvc_err_code */
13453 0, /* saved_adv_err_code */
13454 0, /* saved_adv_err_addr */
13455 0 /* num_of_err */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013456};
13457
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013458static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013459 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13460 0x0000, /* 01 cfg_msw */
13461 0xFFFF, /* 02 disc_enable */
13462 0xFFFF, /* 03 wdtr_able */
13463 0x4444, /* 04 sdtr_speed1 */
13464 0xFFFF, /* 05 start_motor */
13465 0xFFFF, /* 06 tagqng_able */
13466 0xFFFF, /* 07 bios_scan */
13467 0, /* 08 scam_tolerant */
13468 7, /* 09 adapter_scsi_id */
13469 0, /* bios_boot_delay */
13470 3, /* 10 scsi_reset_delay */
13471 0, /* bios_id_lun */
13472 0, /* 11 termination_se */
13473 0, /* termination_lvd */
13474 0xFFE7, /* 12 bios_ctrl */
13475 0x4444, /* 13 sdtr_speed2 */
13476 0x4444, /* 14 sdtr_speed3 */
13477 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13478 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13479 0, /* 16 dvc_cntl */
13480 0x4444, /* 17 sdtr_speed4 */
13481 0, /* 18 serial_number_word1 */
13482 0, /* 19 serial_number_word2 */
13483 0, /* 20 serial_number_word3 */
13484 0, /* 21 check_sum */
13485 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13486 , /* 22-29 oem_name[16] */
13487 0, /* 30 dvc_err_code */
13488 0, /* 31 adv_err_code */
13489 0, /* 32 adv_err_addr */
13490 0, /* 33 saved_dvc_err_code */
13491 0, /* 34 saved_adv_err_code */
13492 0, /* 35 saved_adv_err_addr */
13493 0, /* 36 reserved */
13494 0, /* 37 reserved */
13495 0, /* 38 reserved */
13496 0, /* 39 reserved */
13497 0, /* 40 reserved */
13498 0, /* 41 reserved */
13499 0, /* 42 reserved */
13500 0, /* 43 reserved */
13501 0, /* 44 reserved */
13502 0, /* 45 reserved */
13503 0, /* 46 reserved */
13504 0, /* 47 reserved */
13505 0, /* 48 reserved */
13506 0, /* 49 reserved */
13507 0, /* 50 reserved */
13508 0, /* 51 reserved */
13509 0, /* 52 reserved */
13510 0, /* 53 reserved */
13511 0, /* 54 reserved */
13512 0, /* 55 reserved */
13513 0, /* 56 cisptr_lsw */
13514 0, /* 57 cisprt_msw */
13515 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13516 PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
13517 0, /* 60 reserved */
13518 0, /* 61 reserved */
13519 0, /* 62 reserved */
13520 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013521};
13522
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013523static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013524 0, /* 00 cfg_lsw */
13525 0, /* 01 cfg_msw */
13526 0, /* 02 disc_enable */
13527 0, /* 03 wdtr_able */
13528 0, /* 04 sdtr_speed1 */
13529 0, /* 05 start_motor */
13530 0, /* 06 tagqng_able */
13531 0, /* 07 bios_scan */
13532 0, /* 08 scam_tolerant */
13533 1, /* 09 adapter_scsi_id */
13534 1, /* bios_boot_delay */
13535 1, /* 10 scsi_reset_delay */
13536 1, /* bios_id_lun */
13537 1, /* 11 termination_se */
13538 1, /* termination_lvd */
13539 0, /* 12 bios_ctrl */
13540 0, /* 13 sdtr_speed2 */
13541 0, /* 14 sdtr_speed3 */
13542 1, /* 15 max_host_qng */
13543 1, /* max_dvc_qng */
13544 0, /* 16 dvc_cntl */
13545 0, /* 17 sdtr_speed4 */
13546 0, /* 18 serial_number_word1 */
13547 0, /* 19 serial_number_word2 */
13548 0, /* 20 serial_number_word3 */
13549 0, /* 21 check_sum */
13550 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13551 , /* 22-29 oem_name[16] */
13552 0, /* 30 dvc_err_code */
13553 0, /* 31 adv_err_code */
13554 0, /* 32 adv_err_addr */
13555 0, /* 33 saved_dvc_err_code */
13556 0, /* 34 saved_adv_err_code */
13557 0, /* 35 saved_adv_err_addr */
13558 0, /* 36 reserved */
13559 0, /* 37 reserved */
13560 0, /* 38 reserved */
13561 0, /* 39 reserved */
13562 0, /* 40 reserved */
13563 0, /* 41 reserved */
13564 0, /* 42 reserved */
13565 0, /* 43 reserved */
13566 0, /* 44 reserved */
13567 0, /* 45 reserved */
13568 0, /* 46 reserved */
13569 0, /* 47 reserved */
13570 0, /* 48 reserved */
13571 0, /* 49 reserved */
13572 0, /* 50 reserved */
13573 0, /* 51 reserved */
13574 0, /* 52 reserved */
13575 0, /* 53 reserved */
13576 0, /* 54 reserved */
13577 0, /* 55 reserved */
13578 0, /* 56 cisptr_lsw */
13579 0, /* 57 cisprt_msw */
13580 0, /* 58 subsysvid */
13581 0, /* 59 subsysid */
13582 0, /* 60 reserved */
13583 0, /* 61 reserved */
13584 0, /* 62 reserved */
13585 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013586};
13587
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013588static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013589 ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */
13590 0x0000, /* 01 cfg_msw */
13591 0xFFFF, /* 02 disc_enable */
13592 0xFFFF, /* 03 wdtr_able */
13593 0x5555, /* 04 sdtr_speed1 */
13594 0xFFFF, /* 05 start_motor */
13595 0xFFFF, /* 06 tagqng_able */
13596 0xFFFF, /* 07 bios_scan */
13597 0, /* 08 scam_tolerant */
13598 7, /* 09 adapter_scsi_id */
13599 0, /* bios_boot_delay */
13600 3, /* 10 scsi_reset_delay */
13601 0, /* bios_id_lun */
13602 0, /* 11 termination_se */
13603 0, /* termination_lvd */
13604 0xFFE7, /* 12 bios_ctrl */
13605 0x5555, /* 13 sdtr_speed2 */
13606 0x5555, /* 14 sdtr_speed3 */
13607 ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */
13608 ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
13609 0, /* 16 dvc_cntl */
13610 0x5555, /* 17 sdtr_speed4 */
13611 0, /* 18 serial_number_word1 */
13612 0, /* 19 serial_number_word2 */
13613 0, /* 20 serial_number_word3 */
13614 0, /* 21 check_sum */
13615 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
13616 , /* 22-29 oem_name[16] */
13617 0, /* 30 dvc_err_code */
13618 0, /* 31 adv_err_code */
13619 0, /* 32 adv_err_addr */
13620 0, /* 33 saved_dvc_err_code */
13621 0, /* 34 saved_adv_err_code */
13622 0, /* 35 saved_adv_err_addr */
13623 0, /* 36 reserved */
13624 0, /* 37 reserved */
13625 0, /* 38 reserved */
13626 0, /* 39 reserved */
13627 0, /* 40 reserved */
13628 0, /* 41 reserved */
13629 0, /* 42 reserved */
13630 0, /* 43 reserved */
13631 0, /* 44 reserved */
13632 0, /* 45 reserved */
13633 0, /* 46 reserved */
13634 0, /* 47 reserved */
13635 0, /* 48 reserved */
13636 0, /* 49 reserved */
13637 0, /* 50 reserved */
13638 0, /* 51 reserved */
13639 0, /* 52 reserved */
13640 0, /* 53 reserved */
13641 0, /* 54 reserved */
13642 0, /* 55 reserved */
13643 0, /* 56 cisptr_lsw */
13644 0, /* 57 cisprt_msw */
13645 PCI_VENDOR_ID_ASP, /* 58 subsysvid */
13646 PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
13647 0, /* 60 reserved */
13648 0, /* 61 reserved */
13649 0, /* 62 reserved */
13650 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013651};
13652
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013653static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013654 0, /* 00 cfg_lsw */
13655 0, /* 01 cfg_msw */
13656 0, /* 02 disc_enable */
13657 0, /* 03 wdtr_able */
13658 0, /* 04 sdtr_speed1 */
13659 0, /* 05 start_motor */
13660 0, /* 06 tagqng_able */
13661 0, /* 07 bios_scan */
13662 0, /* 08 scam_tolerant */
13663 1, /* 09 adapter_scsi_id */
13664 1, /* bios_boot_delay */
13665 1, /* 10 scsi_reset_delay */
13666 1, /* bios_id_lun */
13667 1, /* 11 termination_se */
13668 1, /* termination_lvd */
13669 0, /* 12 bios_ctrl */
13670 0, /* 13 sdtr_speed2 */
13671 0, /* 14 sdtr_speed3 */
13672 1, /* 15 max_host_qng */
13673 1, /* max_dvc_qng */
13674 0, /* 16 dvc_cntl */
13675 0, /* 17 sdtr_speed4 */
13676 0, /* 18 serial_number_word1 */
13677 0, /* 19 serial_number_word2 */
13678 0, /* 20 serial_number_word3 */
13679 0, /* 21 check_sum */
13680 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
13681 , /* 22-29 oem_name[16] */
13682 0, /* 30 dvc_err_code */
13683 0, /* 31 adv_err_code */
13684 0, /* 32 adv_err_addr */
13685 0, /* 33 saved_dvc_err_code */
13686 0, /* 34 saved_adv_err_code */
13687 0, /* 35 saved_adv_err_addr */
13688 0, /* 36 reserved */
13689 0, /* 37 reserved */
13690 0, /* 38 reserved */
13691 0, /* 39 reserved */
13692 0, /* 40 reserved */
13693 0, /* 41 reserved */
13694 0, /* 42 reserved */
13695 0, /* 43 reserved */
13696 0, /* 44 reserved */
13697 0, /* 45 reserved */
13698 0, /* 46 reserved */
13699 0, /* 47 reserved */
13700 0, /* 48 reserved */
13701 0, /* 49 reserved */
13702 0, /* 50 reserved */
13703 0, /* 51 reserved */
13704 0, /* 52 reserved */
13705 0, /* 53 reserved */
13706 0, /* 54 reserved */
13707 0, /* 55 reserved */
13708 0, /* 56 cisptr_lsw */
13709 0, /* 57 cisprt_msw */
13710 0, /* 58 subsysvid */
13711 0, /* 59 subsysid */
13712 0, /* 60 reserved */
13713 0, /* 61 reserved */
13714 0, /* 62 reserved */
13715 0 /* 63 reserved */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013716};
13717
13718/*
13719 * Initialize the ADV_DVC_VAR structure.
13720 *
13721 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13722 *
13723 * For a non-fatal error return a warning code. If there are no warnings
13724 * then 0 is returned.
13725 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060013726static int __devinit AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013727{
Matthew Wilcox9649af32007-07-26 21:51:47 -060013728 unsigned short warn_code = 0;
13729 AdvPortAddr iop_base = asc_dvc->iop_base;
13730 struct pci_dev *pdev = to_pci_dev(asc_dvc->cfg->dev);
13731 u16 cmd;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013732 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013733
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013734 asc_dvc->err_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013735
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013736 /*
13737 * Save the state of the PCI Configuration Command Register
13738 * "Parity Error Response Control" Bit. If the bit is clear (0),
13739 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
13740 * DMA parity errors.
13741 */
13742 asc_dvc->cfg->control_flag = 0;
Matthew Wilcox9649af32007-07-26 21:51:47 -060013743 pci_read_config_word(pdev, PCI_COMMAND, &cmd);
13744 if ((cmd & PCI_COMMAND_PARITY) == 0)
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013745 asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013746
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013747 asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
13748 ADV_LIB_VERSION_MINOR;
13749 asc_dvc->cfg->chip_version =
13750 AdvGetChipVersion(iop_base, asc_dvc->bus_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013751
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013752 ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
13753 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
13754 (ushort)ADV_CHIP_ID_BYTE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013755
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013756 ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
13757 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
13758 (ushort)ADV_CHIP_ID_WORD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013759
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013760 /*
13761 * Reset the chip to start and allow register writes.
13762 */
13763 if (AdvFindSignature(iop_base) == 0) {
13764 asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
13765 return ADV_ERROR;
13766 } else {
13767 /*
13768 * The caller must set 'chip_type' to a valid setting.
13769 */
13770 if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
13771 asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
13772 asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
13773 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13774 return ADV_ERROR;
13775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013776
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013777 /*
13778 * Reset Chip.
13779 */
13780 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13781 ADV_CTRL_REG_CMD_RESET);
13782 DvcSleepMilliSecond(100);
13783 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
13784 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013785
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013786 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013787 status = AdvInitFrom38C1600EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013788 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013789 status = AdvInitFrom38C0800EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013790 } else {
Matthew Wilcox9649af32007-07-26 21:51:47 -060013791 status = AdvInitFrom3550EEP(asc_dvc);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013792 }
13793 warn_code |= status;
13794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013795
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013796 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013797}
13798
13799/*
13800 * Initialize the ASC-3550.
13801 *
13802 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
13803 *
13804 * For a non-fatal error return a warning code. If there are no warnings
13805 * then 0 is returned.
13806 *
13807 * Needed after initialization for error recovery.
13808 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013809static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070013810{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013811 AdvPortAddr iop_base;
13812 ushort warn_code;
13813 ADV_DCNT sum;
13814 int begin_addr;
13815 int end_addr;
13816 ushort code_sum;
13817 int word;
13818 int j;
13819 int adv_asc3550_expanded_size;
13820 ADV_CARR_T *carrp;
13821 ADV_DCNT contig_len;
13822 ADV_SDCNT buf_size;
13823 ADV_PADDR carr_paddr;
13824 int i;
13825 ushort scsi_cfg1;
13826 uchar tid;
13827 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
13828 ushort wdtr_able = 0, sdtr_able, tagqng_able;
13829 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070013830
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013831 /* If there is already an error, don't continue. */
13832 if (asc_dvc->err_code != 0) {
13833 return ADV_ERROR;
13834 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013835
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013836 /*
13837 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
13838 */
13839 if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
13840 asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
13841 return ADV_ERROR;
13842 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013843
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013844 warn_code = 0;
13845 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013846
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013847 /*
13848 * Save the RISC memory BIOS region before writing the microcode.
13849 * The BIOS may already be loaded and using its RISC LRAM region
13850 * so its region must be saved and restored.
13851 *
13852 * Note: This code makes the assumption, which is currently true,
13853 * that a chip reset does not clear RISC LRAM.
13854 */
13855 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13856 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13857 bios_mem[i]);
13858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013859
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013860 /*
13861 * Save current per TID negotiated values.
13862 */
13863 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
13864 ushort bios_version, major, minor;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013865
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013866 bios_version =
13867 bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
13868 major = (bios_version >> 12) & 0xF;
13869 minor = (bios_version >> 8) & 0xF;
13870 if (major < 3 || (major == 3 && minor == 1)) {
13871 /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
13872 AdvReadWordLram(iop_base, 0x120, wdtr_able);
13873 } else {
13874 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
13875 }
13876 }
13877 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
13878 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
13879 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
13880 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
13881 max_cmd[tid]);
13882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013883
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013884 /*
13885 * Load the Microcode
13886 *
13887 * Write the microcode image to RISC memory starting at address 0.
13888 */
13889 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
13890 /* Assume the following compressed format of the microcode buffer:
13891 *
13892 * 254 word (508 byte) table indexed by byte code followed
13893 * by the following byte codes:
13894 *
13895 * 1-Byte Code:
13896 * 00: Emit word 0 in table.
13897 * 01: Emit word 1 in table.
13898 * .
13899 * FD: Emit word 253 in table.
13900 *
13901 * Multi-Byte Code:
13902 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
13903 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
13904 */
13905 word = 0;
13906 for (i = 253 * 2; i < _adv_asc3550_size; i++) {
13907 if (_adv_asc3550_buf[i] == 0xff) {
13908 for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
13909 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13910 _adv_asc3550_buf
13911 [i +
13912 3] << 8) |
13913 _adv_asc3550_buf
13914 [i + 2]));
13915 word++;
13916 }
13917 i += 3;
13918 } else if (_adv_asc3550_buf[i] == 0xfe) {
13919 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13920 _adv_asc3550_buf[i +
13921 2]
13922 << 8) |
13923 _adv_asc3550_buf[i +
13924 1]));
13925 i += 2;
13926 word++;
13927 } else {
13928 AdvWriteWordAutoIncLram(iop_base, (((ushort)
13929 _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
13930 word++;
13931 }
13932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013933
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013934 /*
13935 * Set 'word' for later use to clear the rest of memory and save
13936 * the expanded mcode size.
13937 */
13938 word *= 2;
13939 adv_asc3550_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070013940
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013941 /*
13942 * Clear the rest of ASC-3550 Internal RAM (8KB).
13943 */
13944 for (; word < ADV_3550_MEMSIZE; word += 2) {
13945 AdvWriteWordAutoIncLram(iop_base, 0);
13946 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013947
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013948 /*
13949 * Verify the microcode checksum.
13950 */
13951 sum = 0;
13952 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013953
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013954 for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
13955 sum += AdvReadWordAutoIncLram(iop_base);
13956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013957
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013958 if (sum != _adv_asc3550_chksum) {
13959 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
13960 return ADV_ERROR;
13961 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013962
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013963 /*
13964 * Restore the RISC memory BIOS region.
13965 */
13966 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
13967 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
13968 bios_mem[i]);
13969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070013970
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013971 /*
13972 * Calculate and write the microcode code checksum to the microcode
13973 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
13974 */
13975 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
13976 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
13977 code_sum = 0;
13978 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
13979 for (word = begin_addr; word < end_addr; word += 2) {
13980 code_sum += AdvReadWordAutoIncLram(iop_base);
13981 }
13982 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013983
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013984 /*
13985 * Read and save microcode version and date.
13986 */
13987 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
13988 asc_dvc->cfg->mcode_date);
13989 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
13990 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013991
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013992 /*
13993 * Set the chip type to indicate the ASC3550.
13994 */
13995 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013996
Matthew Wilcox27c868c2007-07-26 10:56:23 -040013997 /*
13998 * If the PCI Configuration Command Register "Parity Error Response
13999 * Control" Bit was clear (0), then set the microcode variable
14000 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14001 * to ignore DMA parity errors.
14002 */
14003 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14004 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14005 word |= CONTROL_FLAG_IGNORE_PERR;
14006 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14007 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014008
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014009 /*
14010 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
14011 * threshold of 128 bytes. This register is only accessible to the host.
14012 */
14013 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14014 START_CTL_EMFU | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014015
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014016 /*
14017 * Microcode operating variables for WDTR, SDTR, and command tag
14018 * queuing will be set in AdvInquiryHandling() based on what a
14019 * device reports it is capable of in Inquiry byte 7.
14020 *
14021 * If SCSI Bus Resets have been disabled, then directly set
14022 * SDTR and WDTR from the EEPROM configuration. This will allow
14023 * the BIOS and warm boot to work without a SCSI bus hang on
14024 * the Inquiry caused by host and target mismatched DTR values.
14025 * Without the SCSI Bus Reset, before an Inquiry a device can't
14026 * be assumed to be in Asynchronous, Narrow mode.
14027 */
14028 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14029 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14030 asc_dvc->wdtr_able);
14031 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14032 asc_dvc->sdtr_able);
14033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014034
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014035 /*
14036 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
14037 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
14038 * bitmask. These values determine the maximum SDTR speed negotiated
14039 * with a device.
14040 *
14041 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14042 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14043 * without determining here whether the device supports SDTR.
14044 *
14045 * 4-bit speed SDTR speed name
14046 * =========== ===============
14047 * 0000b (0x0) SDTR disabled
14048 * 0001b (0x1) 5 Mhz
14049 * 0010b (0x2) 10 Mhz
14050 * 0011b (0x3) 20 Mhz (Ultra)
14051 * 0100b (0x4) 40 Mhz (LVD/Ultra2)
14052 * 0101b (0x5) 80 Mhz (LVD2/Ultra3)
14053 * 0110b (0x6) Undefined
14054 * .
14055 * 1111b (0xF) Undefined
14056 */
14057 word = 0;
14058 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14059 if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
14060 /* Set Ultra speed for TID 'tid'. */
14061 word |= (0x3 << (4 * (tid % 4)));
14062 } else {
14063 /* Set Fast speed for TID 'tid'. */
14064 word |= (0x2 << (4 * (tid % 4)));
14065 }
14066 if (tid == 3) { /* Check if done with sdtr_speed1. */
14067 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
14068 word = 0;
14069 } else if (tid == 7) { /* Check if done with sdtr_speed2. */
14070 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
14071 word = 0;
14072 } else if (tid == 11) { /* Check if done with sdtr_speed3. */
14073 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
14074 word = 0;
14075 } else if (tid == 15) { /* Check if done with sdtr_speed4. */
14076 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
14077 /* End of loop. */
14078 }
14079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014080
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014081 /*
14082 * Set microcode operating variable for the disconnect per TID bitmask.
14083 */
14084 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14085 asc_dvc->cfg->disc_enable);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014086
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014087 /*
14088 * Set SCSI_CFG0 Microcode Default Value.
14089 *
14090 * The microcode will set the SCSI_CFG0 register using this value
14091 * after it is started below.
14092 */
14093 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14094 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14095 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014096
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014097 /*
14098 * Determine SCSI_CFG1 Microcode Default Value.
14099 *
14100 * The microcode will set the SCSI_CFG1 register using this value
14101 * after it is started below.
14102 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014103
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014104 /* Read current SCSI_CFG1 Register value. */
14105 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014106
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014107 /*
14108 * If all three connectors are in use, return an error.
14109 */
14110 if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
14111 (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
14112 asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
14113 return ADV_ERROR;
14114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014115
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014116 /*
14117 * If the internal narrow cable is reversed all of the SCSI_CTRL
14118 * register signals will be set. Check for and return an error if
14119 * this condition is found.
14120 */
14121 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14122 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14123 return ADV_ERROR;
14124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014125
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014126 /*
14127 * If this is a differential board and a single-ended device
14128 * is attached to one of the connectors, return an error.
14129 */
14130 if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
14131 asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
14132 return ADV_ERROR;
14133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014135 /*
14136 * If automatic termination control is enabled, then set the
14137 * termination value based on a table listed in a_condor.h.
14138 *
14139 * If manual termination was specified with an EEPROM setting
14140 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
14141 * is ready to be 'ored' into SCSI_CFG1.
14142 */
14143 if (asc_dvc->cfg->termination == 0) {
14144 /*
14145 * The software always controls termination by setting TERM_CTL_SEL.
14146 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
14147 */
14148 asc_dvc->cfg->termination |= TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014149
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014150 switch (scsi_cfg1 & CABLE_DETECT) {
14151 /* TERM_CTL_H: on, TERM_CTL_L: on */
14152 case 0x3:
14153 case 0x7:
14154 case 0xB:
14155 case 0xD:
14156 case 0xE:
14157 case 0xF:
14158 asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
14159 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014160
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014161 /* TERM_CTL_H: on, TERM_CTL_L: off */
14162 case 0x1:
14163 case 0x5:
14164 case 0x9:
14165 case 0xA:
14166 case 0xC:
14167 asc_dvc->cfg->termination |= TERM_CTL_H;
14168 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014169
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014170 /* TERM_CTL_H: off, TERM_CTL_L: off */
14171 case 0x2:
14172 case 0x6:
14173 break;
14174 }
14175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014176
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014177 /*
14178 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
14179 */
14180 scsi_cfg1 &= ~TERM_CTL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014181
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014182 /*
14183 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
14184 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
14185 * referenced, because the hardware internally inverts
14186 * the Termination High and Low bits if TERM_POL is set.
14187 */
14188 scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014189
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014190 /*
14191 * Set SCSI_CFG1 Microcode Default Value
14192 *
14193 * Set filter value and possibly modified termination control
14194 * bits in the Microcode SCSI_CFG1 Register Value.
14195 *
14196 * The microcode will set the SCSI_CFG1 register using this value
14197 * after it is started below.
14198 */
14199 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
14200 FLTR_DISABLE | scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014201
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014202 /*
14203 * Set MEM_CFG Microcode Default Value
14204 *
14205 * The microcode will set the MEM_CFG register using this value
14206 * after it is started below.
14207 *
14208 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14209 * are defined.
14210 *
14211 * ASC-3550 has 8KB internal memory.
14212 */
14213 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14214 BIOS_EN | RAM_SZ_8KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014215
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014216 /*
14217 * Set SEL_MASK Microcode Default Value
14218 *
14219 * The microcode will set the SEL_MASK register using this value
14220 * after it is started below.
14221 */
14222 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14223 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014224
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014225 /*
14226 * Build carrier freelist.
14227 *
14228 * Driver must have already allocated memory and set 'carrier_buf'.
14229 */
14230 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014231
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014232 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14233 asc_dvc->carr_freelist = NULL;
14234 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14235 buf_size = ADV_CARRIER_BUFSIZE;
14236 } else {
14237 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014239
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014240 do {
14241 /*
14242 * Get physical address of the carrier 'carrp'.
14243 */
14244 contig_len = sizeof(ADV_CARR_T);
14245 carr_paddr =
14246 cpu_to_le32(DvcGetPhyAddr
14247 (asc_dvc, NULL, (uchar *)carrp,
14248 (ADV_SDCNT *)&contig_len,
14249 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014250
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014251 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014252
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014253 /*
14254 * If the current carrier is not physically contiguous, then
14255 * maybe there was a page crossing. Try the next carrier aligned
14256 * start address.
14257 */
14258 if (contig_len < sizeof(ADV_CARR_T)) {
14259 carrp++;
14260 continue;
14261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014262
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014263 carrp->carr_pa = carr_paddr;
14264 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014265
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014266 /*
14267 * Insert the carrier at the beginning of the freelist.
14268 */
14269 carrp->next_vpa =
14270 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14271 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014272
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014273 carrp++;
14274 }
14275 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014276
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014277 /*
14278 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14279 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014280
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014281 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14282 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14283 return ADV_ERROR;
14284 }
14285 asc_dvc->carr_freelist = (ADV_CARR_T *)
14286 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014287
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014288 /*
14289 * The first command issued will be placed in the stopper carrier.
14290 */
14291 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014292
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014293 /*
14294 * Set RISC ICQ physical address start value.
14295 */
14296 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014297
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014298 /*
14299 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14300 */
14301 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14302 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14303 return ADV_ERROR;
14304 }
14305 asc_dvc->carr_freelist = (ADV_CARR_T *)
14306 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014307
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014308 /*
14309 * The first command completed by the RISC will be placed in
14310 * the stopper.
14311 *
14312 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14313 * completed the RISC will set the ASC_RQ_STOPPER bit.
14314 */
14315 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014316
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014317 /*
14318 * Set RISC IRQ physical address start value.
14319 */
14320 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14321 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014322
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014323 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14324 (ADV_INTR_ENABLE_HOST_INTR |
14325 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014326
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014327 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14328 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014329
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014330 /* finally, finally, gentlemen, start your engine */
14331 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014332
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014333 /*
14334 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14335 * Resets should be performed. The RISC has to be running
14336 * to issue a SCSI Bus Reset.
14337 */
14338 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14339 /*
14340 * If the BIOS Signature is present in memory, restore the
14341 * BIOS Handshake Configuration Table and do not perform
14342 * a SCSI Bus Reset.
14343 */
14344 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14345 0x55AA) {
14346 /*
14347 * Restore per TID negotiated values.
14348 */
14349 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14350 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14351 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14352 tagqng_able);
14353 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14354 AdvWriteByteLram(iop_base,
14355 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14356 max_cmd[tid]);
14357 }
14358 } else {
14359 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14360 warn_code = ASC_WARN_BUSRESET_ERROR;
14361 }
14362 }
14363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014364
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014365 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014366}
14367
14368/*
14369 * Initialize the ASC-38C0800.
14370 *
14371 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
14372 *
14373 * For a non-fatal error return a warning code. If there are no warnings
14374 * then 0 is returned.
14375 *
14376 * Needed after initialization for error recovery.
14377 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014378static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014379{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014380 AdvPortAddr iop_base;
14381 ushort warn_code;
14382 ADV_DCNT sum;
14383 int begin_addr;
14384 int end_addr;
14385 ushort code_sum;
14386 int word;
14387 int j;
14388 int adv_asc38C0800_expanded_size;
14389 ADV_CARR_T *carrp;
14390 ADV_DCNT contig_len;
14391 ADV_SDCNT buf_size;
14392 ADV_PADDR carr_paddr;
14393 int i;
14394 ushort scsi_cfg1;
14395 uchar byte;
14396 uchar tid;
14397 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
14398 ushort wdtr_able, sdtr_able, tagqng_able;
14399 uchar max_cmd[ADV_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070014400
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014401 /* If there is already an error, don't continue. */
14402 if (asc_dvc->err_code != 0) {
14403 return ADV_ERROR;
14404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014405
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014406 /*
14407 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
14408 */
14409 if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
14410 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
14411 return ADV_ERROR;
14412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014413
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014414 warn_code = 0;
14415 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014416
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014417 /*
14418 * Save the RISC memory BIOS region before writing the microcode.
14419 * The BIOS may already be loaded and using its RISC LRAM region
14420 * so its region must be saved and restored.
14421 *
14422 * Note: This code makes the assumption, which is currently true,
14423 * that a chip reset does not clear RISC LRAM.
14424 */
14425 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14426 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14427 bios_mem[i]);
14428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014429
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014430 /*
14431 * Save current per TID negotiated values.
14432 */
14433 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14434 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14435 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
14436 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14437 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
14438 max_cmd[tid]);
14439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014440
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014441 /*
14442 * RAM BIST (RAM Built-In Self Test)
14443 *
14444 * Address : I/O base + offset 0x38h register (byte).
14445 * Function: Bit 7-6(RW) : RAM mode
14446 * Normal Mode : 0x00
14447 * Pre-test Mode : 0x40
14448 * RAM Test Mode : 0x80
14449 * Bit 5 : unused
14450 * Bit 4(RO) : Done bit
14451 * Bit 3-0(RO) : Status
14452 * Host Error : 0x08
14453 * Int_RAM Error : 0x04
14454 * RISC Error : 0x02
14455 * SCSI Error : 0x01
14456 * No Error : 0x00
14457 *
14458 * Note: RAM BIST code should be put right here, before loading the
14459 * microcode and after saving the RISC memory BIOS region.
14460 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014461
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014462 /*
14463 * LRAM Pre-test
14464 *
14465 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
14466 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
14467 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
14468 * to NORMAL_MODE, return an error too.
14469 */
14470 for (i = 0; i < 2; i++) {
14471 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
14472 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14473 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14474 if ((byte & RAM_TEST_DONE) == 0
14475 || (byte & 0x0F) != PRE_TEST_VALUE) {
14476 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14477 return ADV_ERROR;
14478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014479
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014480 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
14481 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
14482 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
14483 != NORMAL_VALUE) {
14484 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
14485 return ADV_ERROR;
14486 }
14487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014488
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014489 /*
14490 * LRAM Test - It takes about 1.5 ms to run through the test.
14491 *
14492 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
14493 * If Done bit not set or Status not 0, save register byte, set the
14494 * err_code, and return an error.
14495 */
14496 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
14497 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014498
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014499 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
14500 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
14501 /* Get here if Done bit not set or Status not 0. */
14502 asc_dvc->bist_err_code = byte; /* for BIOS display message */
14503 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
14504 return ADV_ERROR;
14505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014506
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014507 /* We need to reset back to normal mode after LRAM test passes. */
14508 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014509
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014510 /*
14511 * Load the Microcode
14512 *
14513 * Write the microcode image to RISC memory starting at address 0.
14514 *
14515 */
14516 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014517
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014518 /* Assume the following compressed format of the microcode buffer:
14519 *
14520 * 254 word (508 byte) table indexed by byte code followed
14521 * by the following byte codes:
14522 *
14523 * 1-Byte Code:
14524 * 00: Emit word 0 in table.
14525 * 01: Emit word 1 in table.
14526 * .
14527 * FD: Emit word 253 in table.
14528 *
14529 * Multi-Byte Code:
14530 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
14531 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
14532 */
14533 word = 0;
14534 for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
14535 if (_adv_asc38C0800_buf[i] == 0xff) {
14536 for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
14537 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14538 _adv_asc38C0800_buf
14539 [i +
14540 3] << 8) |
14541 _adv_asc38C0800_buf
14542 [i + 2]));
14543 word++;
14544 }
14545 i += 3;
14546 } else if (_adv_asc38C0800_buf[i] == 0xfe) {
14547 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14548 _adv_asc38C0800_buf
14549 [i +
14550 2] << 8) |
14551 _adv_asc38C0800_buf[i
14552 +
14553 1]));
14554 i += 2;
14555 word++;
14556 } else {
14557 AdvWriteWordAutoIncLram(iop_base, (((ushort)
14558 _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
14559 word++;
14560 }
14561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014563 /*
14564 * Set 'word' for later use to clear the rest of memory and save
14565 * the expanded mcode size.
14566 */
14567 word *= 2;
14568 adv_asc38C0800_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014569
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014570 /*
14571 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
14572 */
14573 for (; word < ADV_38C0800_MEMSIZE; word += 2) {
14574 AdvWriteWordAutoIncLram(iop_base, 0);
14575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014576
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014577 /*
14578 * Verify the microcode checksum.
14579 */
14580 sum = 0;
14581 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014582
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014583 for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
14584 sum += AdvReadWordAutoIncLram(iop_base);
14585 }
14586 ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014587
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014588 ASC_DBG2(1,
14589 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
14590 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014591
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014592 if (sum != _adv_asc38C0800_chksum) {
14593 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
14594 return ADV_ERROR;
14595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014596
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014597 /*
14598 * Restore the RISC memory BIOS region.
14599 */
14600 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
14601 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
14602 bios_mem[i]);
14603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014604
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014605 /*
14606 * Calculate and write the microcode code checksum to the microcode
14607 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
14608 */
14609 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
14610 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
14611 code_sum = 0;
14612 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
14613 for (word = begin_addr; word < end_addr; word += 2) {
14614 code_sum += AdvReadWordAutoIncLram(iop_base);
14615 }
14616 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014617
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014618 /*
14619 * Read microcode version and date.
14620 */
14621 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
14622 asc_dvc->cfg->mcode_date);
14623 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
14624 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014625
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014626 /*
14627 * Set the chip type to indicate the ASC38C0800.
14628 */
14629 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014630
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014631 /*
14632 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
14633 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
14634 * cable detection and then we are able to read C_DET[3:0].
14635 *
14636 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
14637 * Microcode Default Value' section below.
14638 */
14639 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
14640 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
14641 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014642
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014643 /*
14644 * If the PCI Configuration Command Register "Parity Error Response
14645 * Control" Bit was clear (0), then set the microcode variable
14646 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
14647 * to ignore DMA parity errors.
14648 */
14649 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
14650 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14651 word |= CONTROL_FLAG_IGNORE_PERR;
14652 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
14653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014654
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014655 /*
14656 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
14657 * bits for the default FIFO threshold.
14658 *
14659 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
14660 *
14661 * For DMA Errata #4 set the BC_THRESH_ENB bit.
14662 */
14663 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
14664 BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
14665 READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014666
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014667 /*
14668 * Microcode operating variables for WDTR, SDTR, and command tag
14669 * queuing will be set in AdvInquiryHandling() based on what a
14670 * device reports it is capable of in Inquiry byte 7.
14671 *
14672 * If SCSI Bus Resets have been disabled, then directly set
14673 * SDTR and WDTR from the EEPROM configuration. This will allow
14674 * the BIOS and warm boot to work without a SCSI bus hang on
14675 * the Inquiry caused by host and target mismatched DTR values.
14676 * Without the SCSI Bus Reset, before an Inquiry a device can't
14677 * be assumed to be in Asynchronous, Narrow mode.
14678 */
14679 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
14680 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
14681 asc_dvc->wdtr_able);
14682 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
14683 asc_dvc->sdtr_able);
14684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014685
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014686 /*
14687 * Set microcode operating variables for DISC and SDTR_SPEED1,
14688 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
14689 * configuration values.
14690 *
14691 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
14692 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
14693 * without determining here whether the device supports SDTR.
14694 */
14695 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
14696 asc_dvc->cfg->disc_enable);
14697 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
14698 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
14699 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
14700 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014701
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014702 /*
14703 * Set SCSI_CFG0 Microcode Default Value.
14704 *
14705 * The microcode will set the SCSI_CFG0 register using this value
14706 * after it is started below.
14707 */
14708 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
14709 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
14710 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014711
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014712 /*
14713 * Determine SCSI_CFG1 Microcode Default Value.
14714 *
14715 * The microcode will set the SCSI_CFG1 register using this value
14716 * after it is started below.
14717 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014718
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014719 /* Read current SCSI_CFG1 Register value. */
14720 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014721
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014722 /*
14723 * If the internal narrow cable is reversed all of the SCSI_CTRL
14724 * register signals will be set. Check for and return an error if
14725 * this condition is found.
14726 */
14727 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
14728 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
14729 return ADV_ERROR;
14730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014731
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014732 /*
14733 * All kind of combinations of devices attached to one of four connectors
14734 * are acceptable except HVD device attached. For example, LVD device can
14735 * be attached to SE connector while SE device attached to LVD connector.
14736 * If LVD device attached to SE connector, it only runs up to Ultra speed.
14737 *
14738 * If an HVD device is attached to one of LVD connectors, return an error.
14739 * However, there is no way to detect HVD device attached to SE connectors.
14740 */
14741 if (scsi_cfg1 & HVD) {
14742 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
14743 return ADV_ERROR;
14744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014745
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014746 /*
14747 * If either SE or LVD automatic termination control is enabled, then
14748 * set the termination value based on a table listed in a_condor.h.
14749 *
14750 * If manual termination was specified with an EEPROM setting then
14751 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
14752 * be 'ored' into SCSI_CFG1.
14753 */
14754 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
14755 /* SE automatic termination control is enabled. */
14756 switch (scsi_cfg1 & C_DET_SE) {
14757 /* TERM_SE_HI: on, TERM_SE_LO: on */
14758 case 0x1:
14759 case 0x2:
14760 case 0x3:
14761 asc_dvc->cfg->termination |= TERM_SE;
14762 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014763
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014764 /* TERM_SE_HI: on, TERM_SE_LO: off */
14765 case 0x0:
14766 asc_dvc->cfg->termination |= TERM_SE_HI;
14767 break;
14768 }
14769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014770
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014771 if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
14772 /* LVD automatic termination control is enabled. */
14773 switch (scsi_cfg1 & C_DET_LVD) {
14774 /* TERM_LVD_HI: on, TERM_LVD_LO: on */
14775 case 0x4:
14776 case 0x8:
14777 case 0xC:
14778 asc_dvc->cfg->termination |= TERM_LVD;
14779 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014780
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014781 /* TERM_LVD_HI: off, TERM_LVD_LO: off */
14782 case 0x0:
14783 break;
14784 }
14785 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014786
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014787 /*
14788 * Clear any set TERM_SE and TERM_LVD bits.
14789 */
14790 scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014791
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014792 /*
14793 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
14794 */
14795 scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014796
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014797 /*
14798 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
14799 * and set possibly modified termination control bits in the Microcode
14800 * SCSI_CFG1 Register Value.
14801 */
14802 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014803
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014804 /*
14805 * Set SCSI_CFG1 Microcode Default Value
14806 *
14807 * Set possibly modified termination control and reset DIS_TERM_DRV
14808 * bits in the Microcode SCSI_CFG1 Register Value.
14809 *
14810 * The microcode will set the SCSI_CFG1 register using this value
14811 * after it is started below.
14812 */
14813 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014814
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014815 /*
14816 * Set MEM_CFG Microcode Default Value
14817 *
14818 * The microcode will set the MEM_CFG register using this value
14819 * after it is started below.
14820 *
14821 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
14822 * are defined.
14823 *
14824 * ASC-38C0800 has 16KB internal memory.
14825 */
14826 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
14827 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014828
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014829 /*
14830 * Set SEL_MASK Microcode Default Value
14831 *
14832 * The microcode will set the SEL_MASK register using this value
14833 * after it is started below.
14834 */
14835 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
14836 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014837
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014838 /*
14839 * Build the carrier freelist.
14840 *
14841 * Driver must have already allocated memory and set 'carrier_buf'.
14842 */
14843 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014844
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014845 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
14846 asc_dvc->carr_freelist = NULL;
14847 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
14848 buf_size = ADV_CARRIER_BUFSIZE;
14849 } else {
14850 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
14851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014852
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014853 do {
14854 /*
14855 * Get physical address for the carrier 'carrp'.
14856 */
14857 contig_len = sizeof(ADV_CARR_T);
14858 carr_paddr =
14859 cpu_to_le32(DvcGetPhyAddr
14860 (asc_dvc, NULL, (uchar *)carrp,
14861 (ADV_SDCNT *)&contig_len,
14862 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014863
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014864 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014865
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014866 /*
14867 * If the current carrier is not physically contiguous, then
14868 * maybe there was a page crossing. Try the next carrier aligned
14869 * start address.
14870 */
14871 if (contig_len < sizeof(ADV_CARR_T)) {
14872 carrp++;
14873 continue;
14874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014875
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014876 carrp->carr_pa = carr_paddr;
14877 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014878
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014879 /*
14880 * Insert the carrier at the beginning of the freelist.
14881 */
14882 carrp->next_vpa =
14883 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
14884 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014885
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014886 carrp++;
14887 }
14888 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014889
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014890 /*
14891 * Set-up the Host->RISC Initiator Command Queue (ICQ).
14892 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070014893
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014894 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
14895 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14896 return ADV_ERROR;
14897 }
14898 asc_dvc->carr_freelist = (ADV_CARR_T *)
14899 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014900
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014901 /*
14902 * The first command issued will be placed in the stopper carrier.
14903 */
14904 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014905
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014906 /*
14907 * Set RISC ICQ physical address start value.
14908 * carr_pa is LE, must be native before write
14909 */
14910 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014911
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014912 /*
14913 * Set-up the RISC->Host Initiator Response Queue (IRQ).
14914 */
14915 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
14916 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
14917 return ADV_ERROR;
14918 }
14919 asc_dvc->carr_freelist = (ADV_CARR_T *)
14920 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014921
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014922 /*
14923 * The first command completed by the RISC will be placed in
14924 * the stopper.
14925 *
14926 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
14927 * completed the RISC will set the ASC_RQ_STOPPER bit.
14928 */
14929 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014930
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014931 /*
14932 * Set RISC IRQ physical address start value.
14933 *
14934 * carr_pa is LE, must be native before write *
14935 */
14936 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
14937 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014938
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014939 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
14940 (ADV_INTR_ENABLE_HOST_INTR |
14941 ADV_INTR_ENABLE_GLOBAL_INTR));
Linus Torvalds1da177e2005-04-16 15:20:36 -070014942
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014943 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
14944 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014945
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014946 /* finally, finally, gentlemen, start your engine */
14947 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070014948
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014949 /*
14950 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
14951 * Resets should be performed. The RISC has to be running
14952 * to issue a SCSI Bus Reset.
14953 */
14954 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
14955 /*
14956 * If the BIOS Signature is present in memory, restore the
14957 * BIOS Handshake Configuration Table and do not perform
14958 * a SCSI Bus Reset.
14959 */
14960 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
14961 0x55AA) {
14962 /*
14963 * Restore per TID negotiated values.
14964 */
14965 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
14966 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
14967 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
14968 tagqng_able);
14969 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
14970 AdvWriteByteLram(iop_base,
14971 ASC_MC_NUMBER_OF_MAX_CMD + tid,
14972 max_cmd[tid]);
14973 }
14974 } else {
14975 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
14976 warn_code = ASC_WARN_BUSRESET_ERROR;
14977 }
14978 }
14979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070014980
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014981 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070014982}
14983
14984/*
14985 * Initialize the ASC-38C1600.
14986 *
14987 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
14988 *
14989 * For a non-fatal error return a warning code. If there are no warnings
14990 * then 0 is returned.
14991 *
14992 * Needed after initialization for error recovery.
14993 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014994static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070014995{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040014996 AdvPortAddr iop_base;
14997 ushort warn_code;
14998 ADV_DCNT sum;
14999 int begin_addr;
15000 int end_addr;
15001 ushort code_sum;
15002 long word;
15003 int j;
15004 int adv_asc38C1600_expanded_size;
15005 ADV_CARR_T *carrp;
15006 ADV_DCNT contig_len;
15007 ADV_SDCNT buf_size;
15008 ADV_PADDR carr_paddr;
15009 int i;
15010 ushort scsi_cfg1;
15011 uchar byte;
15012 uchar tid;
15013 ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */
15014 ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
15015 uchar max_cmd[ASC_MAX_TID + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -070015016
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015017 /* If there is already an error, don't continue. */
15018 if (asc_dvc->err_code != 0) {
15019 return ADV_ERROR;
15020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015021
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015022 /*
15023 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
15024 */
15025 if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
15026 asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
15027 return ADV_ERROR;
15028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015029
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015030 warn_code = 0;
15031 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015032
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015033 /*
15034 * Save the RISC memory BIOS region before writing the microcode.
15035 * The BIOS may already be loaded and using its RISC LRAM region
15036 * so its region must be saved and restored.
15037 *
15038 * Note: This code makes the assumption, which is currently true,
15039 * that a chip reset does not clear RISC LRAM.
15040 */
15041 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15042 AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15043 bios_mem[i]);
15044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015045
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015046 /*
15047 * Save current per TID negotiated values.
15048 */
15049 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15050 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15051 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15052 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
15053 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15054 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
15055 max_cmd[tid]);
15056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015057
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015058 /*
15059 * RAM BIST (Built-In Self Test)
15060 *
15061 * Address : I/O base + offset 0x38h register (byte).
15062 * Function: Bit 7-6(RW) : RAM mode
15063 * Normal Mode : 0x00
15064 * Pre-test Mode : 0x40
15065 * RAM Test Mode : 0x80
15066 * Bit 5 : unused
15067 * Bit 4(RO) : Done bit
15068 * Bit 3-0(RO) : Status
15069 * Host Error : 0x08
15070 * Int_RAM Error : 0x04
15071 * RISC Error : 0x02
15072 * SCSI Error : 0x01
15073 * No Error : 0x00
15074 *
15075 * Note: RAM BIST code should be put right here, before loading the
15076 * microcode and after saving the RISC memory BIOS region.
15077 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015078
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015079 /*
15080 * LRAM Pre-test
15081 *
15082 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
15083 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
15084 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
15085 * to NORMAL_MODE, return an error too.
15086 */
15087 for (i = 0; i < 2; i++) {
15088 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
15089 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15090 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15091 if ((byte & RAM_TEST_DONE) == 0
15092 || (byte & 0x0F) != PRE_TEST_VALUE) {
15093 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15094 return ADV_ERROR;
15095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015096
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015097 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
15098 DvcSleepMilliSecond(10); /* Wait for 10ms before reading back. */
15099 if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
15100 != NORMAL_VALUE) {
15101 asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
15102 return ADV_ERROR;
15103 }
15104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015105
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015106 /*
15107 * LRAM Test - It takes about 1.5 ms to run through the test.
15108 *
15109 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
15110 * If Done bit not set or Status not 0, save register byte, set the
15111 * err_code, and return an error.
15112 */
15113 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
15114 DvcSleepMilliSecond(10); /* Wait for 10ms before checking status. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015115
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015116 byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
15117 if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
15118 /* Get here if Done bit not set or Status not 0. */
15119 asc_dvc->bist_err_code = byte; /* for BIOS display message */
15120 asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
15121 return ADV_ERROR;
15122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015123
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015124 /* We need to reset back to normal mode after LRAM test passes. */
15125 AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015126
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015127 /*
15128 * Load the Microcode
15129 *
15130 * Write the microcode image to RISC memory starting at address 0.
15131 *
15132 */
15133 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015134
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015135 /*
15136 * Assume the following compressed format of the microcode buffer:
15137 *
15138 * 254 word (508 byte) table indexed by byte code followed
15139 * by the following byte codes:
15140 *
15141 * 1-Byte Code:
15142 * 00: Emit word 0 in table.
15143 * 01: Emit word 1 in table.
15144 * .
15145 * FD: Emit word 253 in table.
15146 *
15147 * Multi-Byte Code:
15148 * FE WW WW: (3 byte code) Word to emit is the next word WW WW.
15149 * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
15150 */
15151 word = 0;
15152 for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
15153 if (_adv_asc38C1600_buf[i] == 0xff) {
15154 for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
15155 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15156 _adv_asc38C1600_buf
15157 [i +
15158 3] << 8) |
15159 _adv_asc38C1600_buf
15160 [i + 2]));
15161 word++;
15162 }
15163 i += 3;
15164 } else if (_adv_asc38C1600_buf[i] == 0xfe) {
15165 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15166 _adv_asc38C1600_buf
15167 [i +
15168 2] << 8) |
15169 _adv_asc38C1600_buf[i
15170 +
15171 1]));
15172 i += 2;
15173 word++;
15174 } else {
15175 AdvWriteWordAutoIncLram(iop_base, (((ushort)
15176 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
15177 word++;
15178 }
15179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015180
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015181 /*
15182 * Set 'word' for later use to clear the rest of memory and save
15183 * the expanded mcode size.
15184 */
15185 word *= 2;
15186 adv_asc38C1600_expanded_size = word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015187
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015188 /*
15189 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
15190 */
15191 for (; word < ADV_38C1600_MEMSIZE; word += 2) {
15192 AdvWriteWordAutoIncLram(iop_base, 0);
15193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015194
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015195 /*
15196 * Verify the microcode checksum.
15197 */
15198 sum = 0;
15199 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015200
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015201 for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
15202 sum += AdvReadWordAutoIncLram(iop_base);
15203 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015204
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015205 if (sum != _adv_asc38C1600_chksum) {
15206 asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
15207 return ADV_ERROR;
15208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015209
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015210 /*
15211 * Restore the RISC memory BIOS region.
15212 */
15213 for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
15214 AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
15215 bios_mem[i]);
15216 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015217
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015218 /*
15219 * Calculate and write the microcode code checksum to the microcode
15220 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
15221 */
15222 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
15223 AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
15224 code_sum = 0;
15225 AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
15226 for (word = begin_addr; word < end_addr; word += 2) {
15227 code_sum += AdvReadWordAutoIncLram(iop_base);
15228 }
15229 AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015230
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015231 /*
15232 * Read microcode version and date.
15233 */
15234 AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
15235 asc_dvc->cfg->mcode_date);
15236 AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
15237 asc_dvc->cfg->mcode_version);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015238
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015239 /*
15240 * Set the chip type to indicate the ASC38C1600.
15241 */
15242 AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015243
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015244 /*
15245 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
15246 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
15247 * cable detection and then we are able to read C_DET[3:0].
15248 *
15249 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
15250 * Microcode Default Value' section below.
15251 */
15252 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
15253 AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
15254 scsi_cfg1 | DIS_TERM_DRV);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015255
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015256 /*
15257 * If the PCI Configuration Command Register "Parity Error Response
15258 * Control" Bit was clear (0), then set the microcode variable
15259 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
15260 * to ignore DMA parity errors.
15261 */
15262 if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
15263 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15264 word |= CONTROL_FLAG_IGNORE_PERR;
15265 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15266 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015267
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015268 /*
15269 * If the BIOS control flag AIPP (Asynchronous Information
15270 * Phase Protection) disable bit is not set, then set the firmware
15271 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
15272 * AIPP checking and encoding.
15273 */
15274 if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
15275 AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15276 word |= CONTROL_FLAG_ENABLE_AIPP;
15277 AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
15278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015279
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015280 /*
15281 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
15282 * and START_CTL_TH [3:2].
15283 */
15284 AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
15285 FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015286
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015287 /*
15288 * Microcode operating variables for WDTR, SDTR, and command tag
15289 * queuing will be set in AdvInquiryHandling() based on what a
15290 * device reports it is capable of in Inquiry byte 7.
15291 *
15292 * If SCSI Bus Resets have been disabled, then directly set
15293 * SDTR and WDTR from the EEPROM configuration. This will allow
15294 * the BIOS and warm boot to work without a SCSI bus hang on
15295 * the Inquiry caused by host and target mismatched DTR values.
15296 * Without the SCSI Bus Reset, before an Inquiry a device can't
15297 * be assumed to be in Asynchronous, Narrow mode.
15298 */
15299 if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
15300 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
15301 asc_dvc->wdtr_able);
15302 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
15303 asc_dvc->sdtr_able);
15304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015305
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015306 /*
15307 * Set microcode operating variables for DISC and SDTR_SPEED1,
15308 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
15309 * configuration values.
15310 *
15311 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
15312 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
15313 * without determining here whether the device supports SDTR.
15314 */
15315 AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
15316 asc_dvc->cfg->disc_enable);
15317 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
15318 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
15319 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
15320 AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015321
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015322 /*
15323 * Set SCSI_CFG0 Microcode Default Value.
15324 *
15325 * The microcode will set the SCSI_CFG0 register using this value
15326 * after it is started below.
15327 */
15328 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
15329 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
15330 asc_dvc->chip_scsi_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015331
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015332 /*
15333 * Calculate SCSI_CFG1 Microcode Default Value.
15334 *
15335 * The microcode will set the SCSI_CFG1 register using this value
15336 * after it is started below.
15337 *
15338 * Each ASC-38C1600 function has only two cable detect bits.
15339 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
15340 */
15341 scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015342
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015343 /*
15344 * If the cable is reversed all of the SCSI_CTRL register signals
15345 * will be set. Check for and return an error if this condition is
15346 * found.
15347 */
15348 if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
15349 asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
15350 return ADV_ERROR;
15351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015352
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015353 /*
15354 * Each ASC-38C1600 function has two connectors. Only an HVD device
15355 * can not be connected to either connector. An LVD device or SE device
15356 * may be connected to either connecor. If an SE device is connected,
15357 * then at most Ultra speed (20 Mhz) can be used on both connectors.
15358 *
15359 * If an HVD device is attached, return an error.
15360 */
15361 if (scsi_cfg1 & HVD) {
15362 asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
15363 return ADV_ERROR;
15364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015365
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015366 /*
15367 * Each function in the ASC-38C1600 uses only the SE cable detect and
15368 * termination because there are two connectors for each function. Each
15369 * function may use either LVD or SE mode. Corresponding the SE automatic
15370 * termination control EEPROM bits are used for each function. Each
15371 * function has its own EEPROM. If SE automatic control is enabled for
15372 * the function, then set the termination value based on a table listed
15373 * in a_condor.h.
15374 *
15375 * If manual termination is specified in the EEPROM for the function,
15376 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
15377 * ready to be 'ored' into SCSI_CFG1.
15378 */
15379 if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
15380 /* SE automatic termination control is enabled. */
15381 switch (scsi_cfg1 & C_DET_SE) {
15382 /* TERM_SE_HI: on, TERM_SE_LO: on */
15383 case 0x1:
15384 case 0x2:
15385 case 0x3:
15386 asc_dvc->cfg->termination |= TERM_SE;
15387 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015388
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015389 case 0x0:
15390 if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
15391 /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
15392 } else {
15393 /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
15394 asc_dvc->cfg->termination |= TERM_SE_HI;
15395 }
15396 break;
15397 }
15398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015399
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015400 /*
15401 * Clear any set TERM_SE bits.
15402 */
15403 scsi_cfg1 &= ~TERM_SE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015404
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015405 /*
15406 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
15407 */
15408 scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015409
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015410 /*
15411 * Clear Big Endian and Terminator Polarity bits and set possibly
15412 * modified termination control bits in the Microcode SCSI_CFG1
15413 * Register Value.
15414 *
15415 * Big Endian bit is not used even on big endian machines.
15416 */
15417 scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015418
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015419 /*
15420 * Set SCSI_CFG1 Microcode Default Value
15421 *
15422 * Set possibly modified termination control bits in the Microcode
15423 * SCSI_CFG1 Register Value.
15424 *
15425 * The microcode will set the SCSI_CFG1 register using this value
15426 * after it is started below.
15427 */
15428 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015429
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015430 /*
15431 * Set MEM_CFG Microcode Default Value
15432 *
15433 * The microcode will set the MEM_CFG register using this value
15434 * after it is started below.
15435 *
15436 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
15437 * are defined.
15438 *
15439 * ASC-38C1600 has 32KB internal memory.
15440 *
15441 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
15442 * out a special 16K Adv Library and Microcode version. After the issue
15443 * resolved, we should turn back to the 32K support. Both a_condor.h and
15444 * mcode.sas files also need to be updated.
15445 *
15446 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15447 * BIOS_EN | RAM_SZ_32KB);
15448 */
15449 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
15450 BIOS_EN | RAM_SZ_16KB);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015451
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015452 /*
15453 * Set SEL_MASK Microcode Default Value
15454 *
15455 * The microcode will set the SEL_MASK register using this value
15456 * after it is started below.
15457 */
15458 AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
15459 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015460
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015461 /*
15462 * Build the carrier freelist.
15463 *
15464 * Driver must have already allocated memory and set 'carrier_buf'.
15465 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070015466
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015467 ASC_ASSERT(asc_dvc->carrier_buf != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015468
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015469 carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
15470 asc_dvc->carr_freelist = NULL;
15471 if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
15472 buf_size = ADV_CARRIER_BUFSIZE;
15473 } else {
15474 buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
15475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015476
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015477 do {
15478 /*
15479 * Get physical address for the carrier 'carrp'.
15480 */
15481 contig_len = sizeof(ADV_CARR_T);
15482 carr_paddr =
15483 cpu_to_le32(DvcGetPhyAddr
15484 (asc_dvc, NULL, (uchar *)carrp,
15485 (ADV_SDCNT *)&contig_len,
15486 ADV_IS_CARRIER_FLAG));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015487
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015488 buf_size -= sizeof(ADV_CARR_T);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015489
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015490 /*
15491 * If the current carrier is not physically contiguous, then
15492 * maybe there was a page crossing. Try the next carrier aligned
15493 * start address.
15494 */
15495 if (contig_len < sizeof(ADV_CARR_T)) {
15496 carrp++;
15497 continue;
15498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015499
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015500 carrp->carr_pa = carr_paddr;
15501 carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015502
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015503 /*
15504 * Insert the carrier at the beginning of the freelist.
15505 */
15506 carrp->next_vpa =
15507 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
15508 asc_dvc->carr_freelist = carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015509
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015510 carrp++;
15511 }
15512 while (buf_size > 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015513
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015514 /*
15515 * Set-up the Host->RISC Initiator Command Queue (ICQ).
15516 */
15517 if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
15518 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15519 return ADV_ERROR;
15520 }
15521 asc_dvc->carr_freelist = (ADV_CARR_T *)
15522 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015523
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015524 /*
15525 * The first command issued will be placed in the stopper carrier.
15526 */
15527 asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015528
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015529 /*
15530 * Set RISC ICQ physical address start value. Initialize the
15531 * COMMA register to the same value otherwise the RISC will
15532 * prematurely detect a command is available.
15533 */
15534 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
15535 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
15536 le32_to_cpu(asc_dvc->icq_sp->carr_pa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015537
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015538 /*
15539 * Set-up the RISC->Host Initiator Response Queue (IRQ).
15540 */
15541 if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
15542 asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
15543 return ADV_ERROR;
15544 }
15545 asc_dvc->carr_freelist = (ADV_CARR_T *)
15546 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070015547
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015548 /*
15549 * The first command completed by the RISC will be placed in
15550 * the stopper.
15551 *
15552 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
15553 * completed the RISC will set the ASC_RQ_STOPPER bit.
15554 */
15555 asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015556
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015557 /*
15558 * Set RISC IRQ physical address start value.
15559 */
15560 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
15561 asc_dvc->carr_pending_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015562
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015563 AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
15564 (ADV_INTR_ENABLE_HOST_INTR |
15565 ADV_INTR_ENABLE_GLOBAL_INTR));
15566 AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
15567 AdvWriteWordRegister(iop_base, IOPW_PC, word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015568
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015569 /* finally, finally, gentlemen, start your engine */
15570 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015571
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015572 /*
15573 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
15574 * Resets should be performed. The RISC has to be running
15575 * to issue a SCSI Bus Reset.
15576 */
15577 if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
15578 /*
15579 * If the BIOS Signature is present in memory, restore the
15580 * per TID microcode operating variables.
15581 */
15582 if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
15583 0x55AA) {
15584 /*
15585 * Restore per TID negotiated values.
15586 */
15587 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
15588 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
15589 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
15590 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
15591 tagqng_able);
15592 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
15593 AdvWriteByteLram(iop_base,
15594 ASC_MC_NUMBER_OF_MAX_CMD + tid,
15595 max_cmd[tid]);
15596 }
15597 } else {
15598 if (AdvResetSB(asc_dvc) != ADV_TRUE) {
15599 warn_code = ASC_WARN_BUSRESET_ERROR;
15600 }
15601 }
15602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015603
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015604 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015605}
15606
15607/*
15608 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15609 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15610 * all of this is done.
15611 *
15612 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15613 *
15614 * For a non-fatal error return a warning code. If there are no warnings
15615 * then 0 is returned.
15616 *
15617 * Note: Chip is stopped on entry.
15618 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015619static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015620{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015621 AdvPortAddr iop_base;
15622 ushort warn_code;
15623 ADVEEP_3550_CONFIG eep_config;
15624 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015625
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015626 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015627
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015628 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015629
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015630 /*
15631 * Read the board's EEPROM configuration.
15632 *
15633 * Set default values if a bad checksum is found.
15634 */
15635 if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
15636 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015637
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015638 /*
15639 * Set EEPROM default values.
15640 */
15641 for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
15642 *((uchar *)&eep_config + i) =
15643 *((uchar *)&Default_3550_EEPROM_Config + i);
15644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015645
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015646 /*
15647 * Assume the 6 byte board serial number that was read
15648 * from EEPROM is correct even if the EEPROM checksum
15649 * failed.
15650 */
15651 eep_config.serial_number_word3 =
15652 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015653
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015654 eep_config.serial_number_word2 =
15655 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015656
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015657 eep_config.serial_number_word1 =
15658 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015659
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015660 AdvSet3550EEPConfig(iop_base, &eep_config);
15661 }
15662 /*
15663 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
15664 * EEPROM configuration that was read.
15665 *
15666 * This is the mapping of EEPROM fields to Adv Library fields.
15667 */
15668 asc_dvc->wdtr_able = eep_config.wdtr_able;
15669 asc_dvc->sdtr_able = eep_config.sdtr_able;
15670 asc_dvc->ultra_able = eep_config.ultra_able;
15671 asc_dvc->tagqng_able = eep_config.tagqng_able;
15672 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15673 asc_dvc->max_host_qng = eep_config.max_host_qng;
15674 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15675 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15676 asc_dvc->start_motor = eep_config.start_motor;
15677 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15678 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15679 asc_dvc->no_scam = eep_config.scam_tolerant;
15680 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15681 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15682 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015683
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015684 /*
15685 * Set the host maximum queuing (max. 253, min. 16) and the per device
15686 * maximum queuing (max. 63, min. 4).
15687 */
15688 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15689 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15690 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15691 /* If the value is zero, assume it is uninitialized. */
15692 if (eep_config.max_host_qng == 0) {
15693 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15694 } else {
15695 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15696 }
15697 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015698
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015699 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15700 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15701 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15702 /* If the value is zero, assume it is uninitialized. */
15703 if (eep_config.max_dvc_qng == 0) {
15704 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15705 } else {
15706 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15707 }
15708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015709
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015710 /*
15711 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15712 * set 'max_dvc_qng' to 'max_host_qng'.
15713 */
15714 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15715 eep_config.max_dvc_qng = eep_config.max_host_qng;
15716 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015717
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015718 /*
15719 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15720 * values based on possibly adjusted EEPROM values.
15721 */
15722 asc_dvc->max_host_qng = eep_config.max_host_qng;
15723 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015724
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015725 /*
15726 * If the EEPROM 'termination' field is set to automatic (0), then set
15727 * the ADV_DVC_CFG 'termination' field to automatic also.
15728 *
15729 * If the termination is specified with a non-zero 'termination'
15730 * value check that a legal value is set and set the ADV_DVC_CFG
15731 * 'termination' field appropriately.
15732 */
15733 if (eep_config.termination == 0) {
15734 asc_dvc->cfg->termination = 0; /* auto termination */
15735 } else {
15736 /* Enable manual control with low off / high off. */
15737 if (eep_config.termination == 1) {
15738 asc_dvc->cfg->termination = TERM_CTL_SEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015739
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015740 /* Enable manual control with low off / high on. */
15741 } else if (eep_config.termination == 2) {
15742 asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015743
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015744 /* Enable manual control with low on / high on. */
15745 } else if (eep_config.termination == 3) {
15746 asc_dvc->cfg->termination =
15747 TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
15748 } else {
15749 /*
15750 * The EEPROM 'termination' field contains a bad value. Use
15751 * automatic termination instead.
15752 */
15753 asc_dvc->cfg->termination = 0;
15754 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15755 }
15756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015757
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015758 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015759}
15760
15761/*
15762 * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
15763 * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
15764 * all of this is done.
15765 *
15766 * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
15767 *
15768 * For a non-fatal error return a warning code. If there are no warnings
15769 * then 0 is returned.
15770 *
15771 * Note: Chip is stopped on entry.
15772 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015773static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015774{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015775 AdvPortAddr iop_base;
15776 ushort warn_code;
15777 ADVEEP_38C0800_CONFIG eep_config;
15778 int i;
15779 uchar tid, termination;
15780 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015781
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015782 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015783
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015784 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015785
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015786 /*
15787 * Read the board's EEPROM configuration.
15788 *
15789 * Set default values if a bad checksum is found.
15790 */
15791 if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
15792 eep_config.check_sum) {
15793 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015794
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015795 /*
15796 * Set EEPROM default values.
15797 */
15798 for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
15799 *((uchar *)&eep_config + i) =
15800 *((uchar *)&Default_38C0800_EEPROM_Config + i);
15801 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015802
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015803 /*
15804 * Assume the 6 byte board serial number that was read
15805 * from EEPROM is correct even if the EEPROM checksum
15806 * failed.
15807 */
15808 eep_config.serial_number_word3 =
15809 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015810
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015811 eep_config.serial_number_word2 =
15812 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015813
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015814 eep_config.serial_number_word1 =
15815 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015816
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015817 AdvSet38C0800EEPConfig(iop_base, &eep_config);
15818 }
15819 /*
15820 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
15821 * EEPROM configuration that was read.
15822 *
15823 * This is the mapping of EEPROM fields to Adv Library fields.
15824 */
15825 asc_dvc->wdtr_able = eep_config.wdtr_able;
15826 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
15827 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
15828 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
15829 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
15830 asc_dvc->tagqng_able = eep_config.tagqng_able;
15831 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
15832 asc_dvc->max_host_qng = eep_config.max_host_qng;
15833 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
15834 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
15835 asc_dvc->start_motor = eep_config.start_motor;
15836 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
15837 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
15838 asc_dvc->no_scam = eep_config.scam_tolerant;
15839 asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
15840 asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
15841 asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015842
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015843 /*
15844 * For every Target ID if any of its 'sdtr_speed[1234]' bits
15845 * are set, then set an 'sdtr_able' bit for it.
15846 */
15847 asc_dvc->sdtr_able = 0;
15848 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
15849 if (tid == 0) {
15850 sdtr_speed = asc_dvc->sdtr_speed1;
15851 } else if (tid == 4) {
15852 sdtr_speed = asc_dvc->sdtr_speed2;
15853 } else if (tid == 8) {
15854 sdtr_speed = asc_dvc->sdtr_speed3;
15855 } else if (tid == 12) {
15856 sdtr_speed = asc_dvc->sdtr_speed4;
15857 }
15858 if (sdtr_speed & ADV_MAX_TID) {
15859 asc_dvc->sdtr_able |= (1 << tid);
15860 }
15861 sdtr_speed >>= 4;
15862 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015863
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015864 /*
15865 * Set the host maximum queuing (max. 253, min. 16) and the per device
15866 * maximum queuing (max. 63, min. 4).
15867 */
15868 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
15869 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15870 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
15871 /* If the value is zero, assume it is uninitialized. */
15872 if (eep_config.max_host_qng == 0) {
15873 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
15874 } else {
15875 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
15876 }
15877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015878
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015879 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
15880 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15881 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
15882 /* If the value is zero, assume it is uninitialized. */
15883 if (eep_config.max_dvc_qng == 0) {
15884 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
15885 } else {
15886 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
15887 }
15888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015889
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015890 /*
15891 * If 'max_dvc_qng' is greater than 'max_host_qng', then
15892 * set 'max_dvc_qng' to 'max_host_qng'.
15893 */
15894 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
15895 eep_config.max_dvc_qng = eep_config.max_host_qng;
15896 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015897
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015898 /*
15899 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
15900 * values based on possibly adjusted EEPROM values.
15901 */
15902 asc_dvc->max_host_qng = eep_config.max_host_qng;
15903 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015904
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015905 /*
15906 * If the EEPROM 'termination' field is set to automatic (0), then set
15907 * the ADV_DVC_CFG 'termination' field to automatic also.
15908 *
15909 * If the termination is specified with a non-zero 'termination'
15910 * value check that a legal value is set and set the ADV_DVC_CFG
15911 * 'termination' field appropriately.
15912 */
15913 if (eep_config.termination_se == 0) {
15914 termination = 0; /* auto termination for SE */
15915 } else {
15916 /* Enable manual control with low off / high off. */
15917 if (eep_config.termination_se == 1) {
15918 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015919
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015920 /* Enable manual control with low off / high on. */
15921 } else if (eep_config.termination_se == 2) {
15922 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015923
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015924 /* Enable manual control with low on / high on. */
15925 } else if (eep_config.termination_se == 3) {
15926 termination = TERM_SE;
15927 } else {
15928 /*
15929 * The EEPROM 'termination_se' field contains a bad value.
15930 * Use automatic termination instead.
15931 */
15932 termination = 0;
15933 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15934 }
15935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015936
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015937 if (eep_config.termination_lvd == 0) {
15938 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
15939 } else {
15940 /* Enable manual control with low off / high off. */
15941 if (eep_config.termination_lvd == 1) {
15942 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015943
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015944 /* Enable manual control with low off / high on. */
15945 } else if (eep_config.termination_lvd == 2) {
15946 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015947
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015948 /* Enable manual control with low on / high on. */
15949 } else if (eep_config.termination_lvd == 3) {
15950 asc_dvc->cfg->termination = termination | TERM_LVD;
15951 } else {
15952 /*
15953 * The EEPROM 'termination_lvd' field contains a bad value.
15954 * Use automatic termination instead.
15955 */
15956 asc_dvc->cfg->termination = termination;
15957 warn_code |= ASC_WARN_EEPROM_TERMINATION;
15958 }
15959 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070015960
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015961 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015962}
15963
15964/*
15965 * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
15966 * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
15967 * all of this is done.
15968 *
15969 * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
15970 *
15971 * For a non-fatal error return a warning code. If there are no warnings
15972 * then 0 is returned.
15973 *
15974 * Note: Chip is stopped on entry.
15975 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060015976static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070015977{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015978 AdvPortAddr iop_base;
15979 ushort warn_code;
15980 ADVEEP_38C1600_CONFIG eep_config;
15981 int i;
15982 uchar tid, termination;
15983 ushort sdtr_speed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015984
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015985 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015986
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015987 warn_code = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015988
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015989 /*
15990 * Read the board's EEPROM configuration.
15991 *
15992 * Set default values if a bad checksum is found.
15993 */
15994 if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
15995 eep_config.check_sum) {
15996 warn_code |= ASC_WARN_EEPROM_CHKSUM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070015997
Matthew Wilcox27c868c2007-07-26 10:56:23 -040015998 /*
15999 * Set EEPROM default values.
16000 */
16001 for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
16002 if (i == 1
16003 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
16004 0) {
16005 /*
16006 * Set Function 1 EEPROM Word 0 MSB
16007 *
16008 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
16009 * EEPROM bits.
16010 *
16011 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
16012 * old Mac system booting problem. The Expansion ROM must
16013 * be disabled in Function 1 for these systems.
16014 *
16015 */
16016 *((uchar *)&eep_config + i) =
16017 ((*
16018 ((uchar *)&Default_38C1600_EEPROM_Config
16019 +
16020 i)) &
16021 (~
16022 (((ADV_EEPROM_BIOS_ENABLE |
16023 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016024
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016025 /*
16026 * Set the INTAB (bit 11) if the GPIO 0 input indicates
16027 * the Function 1 interrupt line is wired to INTA.
16028 *
16029 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
16030 * 1 - Function 1 interrupt line wired to INT A.
16031 * 0 - Function 1 interrupt line wired to INT B.
16032 *
16033 * Note: Adapter boards always have Function 0 wired to INTA.
16034 * Put all 5 GPIO bits in input mode and then read
16035 * their input values.
16036 */
16037 AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
16038 0);
16039 if (AdvReadByteRegister
16040 (iop_base, IOPB_GPIO_DATA) & 0x01) {
16041 /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
16042 *((uchar *)&eep_config + i) |=
16043 ((ADV_EEPROM_INTAB >> 8) & 0xFF);
16044 }
16045 } else {
16046 *((uchar *)&eep_config + i) =
16047 *((uchar *)&Default_38C1600_EEPROM_Config
16048 + i);
16049 }
16050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016051
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016052 /*
16053 * Assume the 6 byte board serial number that was read
16054 * from EEPROM is correct even if the EEPROM checksum
16055 * failed.
16056 */
16057 eep_config.serial_number_word3 =
16058 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016059
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016060 eep_config.serial_number_word2 =
16061 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016062
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016063 eep_config.serial_number_word1 =
16064 AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016065
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016066 AdvSet38C1600EEPConfig(iop_base, &eep_config);
16067 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016068
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016069 /*
16070 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
16071 * EEPROM configuration that was read.
16072 *
16073 * This is the mapping of EEPROM fields to Adv Library fields.
16074 */
16075 asc_dvc->wdtr_able = eep_config.wdtr_able;
16076 asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
16077 asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
16078 asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
16079 asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
16080 asc_dvc->ppr_able = 0;
16081 asc_dvc->tagqng_able = eep_config.tagqng_able;
16082 asc_dvc->cfg->disc_enable = eep_config.disc_enable;
16083 asc_dvc->max_host_qng = eep_config.max_host_qng;
16084 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
16085 asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
16086 asc_dvc->start_motor = eep_config.start_motor;
16087 asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
16088 asc_dvc->bios_ctrl = eep_config.bios_ctrl;
16089 asc_dvc->no_scam = eep_config.scam_tolerant;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016090
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016091 /*
16092 * For every Target ID if any of its 'sdtr_speed[1234]' bits
16093 * are set, then set an 'sdtr_able' bit for it.
16094 */
16095 asc_dvc->sdtr_able = 0;
16096 for (tid = 0; tid <= ASC_MAX_TID; tid++) {
16097 if (tid == 0) {
16098 sdtr_speed = asc_dvc->sdtr_speed1;
16099 } else if (tid == 4) {
16100 sdtr_speed = asc_dvc->sdtr_speed2;
16101 } else if (tid == 8) {
16102 sdtr_speed = asc_dvc->sdtr_speed3;
16103 } else if (tid == 12) {
16104 sdtr_speed = asc_dvc->sdtr_speed4;
16105 }
16106 if (sdtr_speed & ASC_MAX_TID) {
16107 asc_dvc->sdtr_able |= (1 << tid);
16108 }
16109 sdtr_speed >>= 4;
16110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016111
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016112 /*
16113 * Set the host maximum queuing (max. 253, min. 16) and the per device
16114 * maximum queuing (max. 63, min. 4).
16115 */
16116 if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
16117 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16118 } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
16119 /* If the value is zero, assume it is uninitialized. */
16120 if (eep_config.max_host_qng == 0) {
16121 eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
16122 } else {
16123 eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
16124 }
16125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016126
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016127 if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
16128 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16129 } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
16130 /* If the value is zero, assume it is uninitialized. */
16131 if (eep_config.max_dvc_qng == 0) {
16132 eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
16133 } else {
16134 eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
16135 }
16136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016137
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016138 /*
16139 * If 'max_dvc_qng' is greater than 'max_host_qng', then
16140 * set 'max_dvc_qng' to 'max_host_qng'.
16141 */
16142 if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
16143 eep_config.max_dvc_qng = eep_config.max_host_qng;
16144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016145
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016146 /*
16147 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
16148 * values based on possibly adjusted EEPROM values.
16149 */
16150 asc_dvc->max_host_qng = eep_config.max_host_qng;
16151 asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016152
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016153 /*
16154 * If the EEPROM 'termination' field is set to automatic (0), then set
16155 * the ASC_DVC_CFG 'termination' field to automatic also.
16156 *
16157 * If the termination is specified with a non-zero 'termination'
16158 * value check that a legal value is set and set the ASC_DVC_CFG
16159 * 'termination' field appropriately.
16160 */
16161 if (eep_config.termination_se == 0) {
16162 termination = 0; /* auto termination for SE */
16163 } else {
16164 /* Enable manual control with low off / high off. */
16165 if (eep_config.termination_se == 1) {
16166 termination = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016167
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016168 /* Enable manual control with low off / high on. */
16169 } else if (eep_config.termination_se == 2) {
16170 termination = TERM_SE_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016171
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016172 /* Enable manual control with low on / high on. */
16173 } else if (eep_config.termination_se == 3) {
16174 termination = TERM_SE;
16175 } else {
16176 /*
16177 * The EEPROM 'termination_se' field contains a bad value.
16178 * Use automatic termination instead.
16179 */
16180 termination = 0;
16181 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16182 }
16183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016184
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016185 if (eep_config.termination_lvd == 0) {
16186 asc_dvc->cfg->termination = termination; /* auto termination for LVD */
16187 } else {
16188 /* Enable manual control with low off / high off. */
16189 if (eep_config.termination_lvd == 1) {
16190 asc_dvc->cfg->termination = termination;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016191
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016192 /* Enable manual control with low off / high on. */
16193 } else if (eep_config.termination_lvd == 2) {
16194 asc_dvc->cfg->termination = termination | TERM_LVD_HI;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016195
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016196 /* Enable manual control with low on / high on. */
16197 } else if (eep_config.termination_lvd == 3) {
16198 asc_dvc->cfg->termination = termination | TERM_LVD;
16199 } else {
16200 /*
16201 * The EEPROM 'termination_lvd' field contains a bad value.
16202 * Use automatic termination instead.
16203 */
16204 asc_dvc->cfg->termination = termination;
16205 warn_code |= ASC_WARN_EEPROM_TERMINATION;
16206 }
16207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016208
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016209 return warn_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016210}
16211
16212/*
16213 * Read EEPROM configuration into the specified buffer.
16214 *
16215 * Return a checksum based on the EEPROM configuration read.
16216 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016217static ushort __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016218AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16219{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016220 ushort wval, chksum;
16221 ushort *wbuf;
16222 int eep_addr;
16223 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016224
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016225 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16226 wbuf = (ushort *)cfg_buf;
16227 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016228
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016229 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16230 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16231 wval = AdvReadEEPWord(iop_base, eep_addr);
16232 chksum += wval; /* Checksum is calculated from word values. */
16233 if (*charfields++) {
16234 *wbuf = le16_to_cpu(wval);
16235 } else {
16236 *wbuf = wval;
16237 }
16238 }
16239 /* Read checksum word. */
16240 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16241 wbuf++;
16242 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016243
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016244 /* Read rest of EEPROM not covered by the checksum. */
16245 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16246 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16247 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16248 if (*charfields++) {
16249 *wbuf = le16_to_cpu(*wbuf);
16250 }
16251 }
16252 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016253}
16254
16255/*
16256 * Read EEPROM configuration into the specified buffer.
16257 *
16258 * Return a checksum based on the EEPROM configuration read.
16259 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016260static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016261AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016262{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016263 ushort wval, chksum;
16264 ushort *wbuf;
16265 int eep_addr;
16266 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016267
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016268 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16269 wbuf = (ushort *)cfg_buf;
16270 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016271
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016272 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16273 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16274 wval = AdvReadEEPWord(iop_base, eep_addr);
16275 chksum += wval; /* Checksum is calculated from word values. */
16276 if (*charfields++) {
16277 *wbuf = le16_to_cpu(wval);
16278 } else {
16279 *wbuf = wval;
16280 }
16281 }
16282 /* Read checksum word. */
16283 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16284 wbuf++;
16285 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016286
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016287 /* Read rest of EEPROM not covered by the checksum. */
16288 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16289 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16290 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16291 if (*charfields++) {
16292 *wbuf = le16_to_cpu(*wbuf);
16293 }
16294 }
16295 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016296}
16297
16298/*
16299 * Read EEPROM configuration into the specified buffer.
16300 *
16301 * Return a checksum based on the EEPROM configuration read.
16302 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016303static ushort __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016304AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016305{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016306 ushort wval, chksum;
16307 ushort *wbuf;
16308 int eep_addr;
16309 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016310
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016311 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16312 wbuf = (ushort *)cfg_buf;
16313 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016314
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016315 for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
16316 eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
16317 wval = AdvReadEEPWord(iop_base, eep_addr);
16318 chksum += wval; /* Checksum is calculated from word values. */
16319 if (*charfields++) {
16320 *wbuf = le16_to_cpu(wval);
16321 } else {
16322 *wbuf = wval;
16323 }
16324 }
16325 /* Read checksum word. */
16326 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16327 wbuf++;
16328 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016329
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016330 /* Read rest of EEPROM not covered by the checksum. */
16331 for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
16332 eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
16333 *wbuf = AdvReadEEPWord(iop_base, eep_addr);
16334 if (*charfields++) {
16335 *wbuf = le16_to_cpu(*wbuf);
16336 }
16337 }
16338 return chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016339}
16340
16341/*
16342 * Read the EEPROM from specified location
16343 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016344static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016345{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016346 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16347 ASC_EEP_CMD_READ | eep_word_addr);
16348 AdvWaitEEPCmd(iop_base);
16349 return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016350}
16351
16352/*
16353 * Wait for EEPROM command to complete
16354 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016355static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016356{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016357 int eep_delay_ms;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016358
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016359 for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
16360 if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
16361 ASC_EEP_CMD_DONE) {
16362 break;
16363 }
16364 DvcSleepMilliSecond(1);
16365 }
16366 if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
16367 0) {
16368 ASC_ASSERT(0);
16369 }
16370 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016371}
16372
16373/*
16374 * Write the EEPROM from 'cfg_buf'.
16375 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016376void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -070016377AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
16378{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016379 ushort *wbuf;
16380 ushort addr, chksum;
16381 ushort *charfields;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016382
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016383 wbuf = (ushort *)cfg_buf;
16384 charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
16385 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016386
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016387 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16388 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016389
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016390 /*
16391 * Write EEPROM from word 0 to word 20.
16392 */
16393 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16394 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16395 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016396
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016397 if (*charfields++) {
16398 word = cpu_to_le16(*wbuf);
16399 } else {
16400 word = *wbuf;
16401 }
16402 chksum += *wbuf; /* Checksum is calculated from word values. */
16403 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16404 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16405 ASC_EEP_CMD_WRITE | addr);
16406 AdvWaitEEPCmd(iop_base);
16407 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016409
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016410 /*
16411 * Write EEPROM checksum at word 21.
16412 */
16413 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16414 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16415 AdvWaitEEPCmd(iop_base);
16416 wbuf++;
16417 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016418
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016419 /*
16420 * Write EEPROM OEM name at words 22 to 29.
16421 */
16422 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16423 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16424 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016425
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016426 if (*charfields++) {
16427 word = cpu_to_le16(*wbuf);
16428 } else {
16429 word = *wbuf;
16430 }
16431 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16432 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16433 ASC_EEP_CMD_WRITE | addr);
16434 AdvWaitEEPCmd(iop_base);
16435 }
16436 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16437 AdvWaitEEPCmd(iop_base);
16438 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016439}
16440
16441/*
16442 * Write the EEPROM from 'cfg_buf'.
16443 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016444void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016445AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016446{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016447 ushort *wbuf;
16448 ushort *charfields;
16449 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016450
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016451 wbuf = (ushort *)cfg_buf;
16452 charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
16453 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016454
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016455 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16456 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016457
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016458 /*
16459 * Write EEPROM from word 0 to word 20.
16460 */
16461 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16462 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16463 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016464
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016465 if (*charfields++) {
16466 word = cpu_to_le16(*wbuf);
16467 } else {
16468 word = *wbuf;
16469 }
16470 chksum += *wbuf; /* Checksum is calculated from word values. */
16471 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16472 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16473 ASC_EEP_CMD_WRITE | addr);
16474 AdvWaitEEPCmd(iop_base);
16475 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016477
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016478 /*
16479 * Write EEPROM checksum at word 21.
16480 */
16481 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16482 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16483 AdvWaitEEPCmd(iop_base);
16484 wbuf++;
16485 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016486
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016487 /*
16488 * Write EEPROM OEM name at words 22 to 29.
16489 */
16490 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16491 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16492 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016493
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016494 if (*charfields++) {
16495 word = cpu_to_le16(*wbuf);
16496 } else {
16497 word = *wbuf;
16498 }
16499 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16500 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16501 ASC_EEP_CMD_WRITE | addr);
16502 AdvWaitEEPCmd(iop_base);
16503 }
16504 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16505 AdvWaitEEPCmd(iop_base);
16506 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016507}
16508
16509/*
16510 * Write the EEPROM from 'cfg_buf'.
16511 */
Matthew Wilcox78e77d82007-07-29 21:46:15 -060016512void __devinit
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016513AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016514{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016515 ushort *wbuf;
16516 ushort *charfields;
16517 ushort addr, chksum;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016518
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016519 wbuf = (ushort *)cfg_buf;
16520 charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
16521 chksum = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016522
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016523 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
16524 AdvWaitEEPCmd(iop_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016525
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016526 /*
16527 * Write EEPROM from word 0 to word 20.
16528 */
16529 for (addr = ADV_EEP_DVC_CFG_BEGIN;
16530 addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
16531 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016532
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016533 if (*charfields++) {
16534 word = cpu_to_le16(*wbuf);
16535 } else {
16536 word = *wbuf;
16537 }
16538 chksum += *wbuf; /* Checksum is calculated from word values. */
16539 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16540 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16541 ASC_EEP_CMD_WRITE | addr);
16542 AdvWaitEEPCmd(iop_base);
16543 DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
16544 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016545
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016546 /*
16547 * Write EEPROM checksum at word 21.
16548 */
16549 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
16550 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
16551 AdvWaitEEPCmd(iop_base);
16552 wbuf++;
16553 charfields++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016554
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016555 /*
16556 * Write EEPROM OEM name at words 22 to 29.
16557 */
16558 for (addr = ADV_EEP_DVC_CTL_BEGIN;
16559 addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
16560 ushort word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016561
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016562 if (*charfields++) {
16563 word = cpu_to_le16(*wbuf);
16564 } else {
16565 word = *wbuf;
16566 }
16567 AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
16568 AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
16569 ASC_EEP_CMD_WRITE | addr);
16570 AdvWaitEEPCmd(iop_base);
16571 }
16572 AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
16573 AdvWaitEEPCmd(iop_base);
16574 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016575}
16576
16577/* a_advlib.c */
16578/*
16579 * AdvExeScsiQueue() - Send a request to the RISC microcode program.
16580 *
16581 * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
16582 * add the carrier to the ICQ (Initiator Command Queue), and tickle the
16583 * RISC to notify it a new command is ready to be executed.
16584 *
16585 * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
16586 * set to SCSI_MAX_RETRY.
16587 *
16588 * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
16589 * for DMA addresses or math operations are byte swapped to little-endian
16590 * order.
16591 *
16592 * Return:
16593 * ADV_SUCCESS(1) - The request was successfully queued.
16594 * ADV_BUSY(0) - Resource unavailable; Retry again after pending
16595 * request completes.
16596 * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure
16597 * host IC error.
16598 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016599static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016600{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016601 ulong last_int_level;
16602 AdvPortAddr iop_base;
16603 ADV_DCNT req_size;
16604 ADV_PADDR req_paddr;
16605 ADV_CARR_T *new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016606
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016607 ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070016608
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016609 /*
16610 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
16611 */
16612 if (scsiq->target_id > ADV_MAX_TID) {
16613 scsiq->host_status = QHSTA_M_INVALID_DEVICE;
16614 scsiq->done_status = QD_WITH_ERROR;
16615 return ADV_ERROR;
16616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016617
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016618 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016619
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016620 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016621
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016622 /*
16623 * Allocate a carrier ensuring at least one carrier always
16624 * remains on the freelist and initialize fields.
16625 */
16626 if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
16627 DvcLeaveCritical(last_int_level);
16628 return ADV_BUSY;
16629 }
16630 asc_dvc->carr_freelist = (ADV_CARR_T *)
16631 ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
16632 asc_dvc->carr_pending_cnt++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016633
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016634 /*
16635 * Set the carrier to be a stopper by setting 'next_vpa'
16636 * to the stopper value. The current stopper will be changed
16637 * below to point to the new stopper.
16638 */
16639 new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016640
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016641 /*
16642 * Clear the ADV_SCSI_REQ_Q done flag.
16643 */
16644 scsiq->a_flag &= ~ADV_SCSIQ_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016645
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016646 req_size = sizeof(ADV_SCSI_REQ_Q);
16647 req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
16648 (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016649
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016650 ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
16651 ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016652
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016653 /* Wait for assertion before making little-endian */
16654 req_paddr = cpu_to_le32(req_paddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016655
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016656 /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
16657 scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
16658 scsiq->scsiq_rptr = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016659
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016660 scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
16661 /*
16662 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
16663 * order during initialization.
16664 */
16665 scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016666
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016667 /*
16668 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
16669 * the microcode. The newly allocated stopper will become the new
16670 * stopper.
16671 */
16672 asc_dvc->icq_sp->areq_vpa = req_paddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016673
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016674 /*
16675 * Set the 'next_vpa' pointer for the old stopper to be the
16676 * physical address of the new stopper. The RISC can only
16677 * follow physical addresses.
16678 */
16679 asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016680
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016681 /*
16682 * Set the host adapter stopper pointer to point to the new carrier.
16683 */
16684 asc_dvc->icq_sp = new_carrp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016685
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016686 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16687 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16688 /*
16689 * Tickle the RISC to tell it to read its Command Queue Head pointer.
16690 */
16691 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
16692 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16693 /*
16694 * Clear the tickle value. In the ASC-3550 the RISC flag
16695 * command 'clr_tickle_a' does not work unless the host
16696 * value is cleared.
16697 */
16698 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16699 ADV_TICKLE_NOP);
16700 }
16701 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16702 /*
16703 * Notify the RISC a carrier is ready by writing the physical
16704 * address of the new carrier stopper to the COMMA register.
16705 */
16706 AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
16707 le32_to_cpu(new_carrp->carr_pa));
16708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016709
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016710 DvcLeaveCritical(last_int_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016711
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016712 return ADV_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016713}
16714
16715/*
16716 * Reset SCSI Bus and purge all outstanding requests.
16717 *
16718 * Return Value:
16719 * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
16720 * ADV_FALSE(0) - Microcode command failed.
16721 * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
16722 * may be hung which requires driver recovery.
16723 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016724static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016725{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016726 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016727
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016728 /*
16729 * Send the SCSI Bus Reset idle start idle command which asserts
16730 * the SCSI Bus Reset signal.
16731 */
16732 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 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 /*
16738 * Delay for the specified SCSI Bus Reset hold time.
16739 *
16740 * The hold time delay is done on the host because the RISC has no
16741 * microsecond accurate timer.
16742 */
16743 DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016744
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016745 /*
16746 * Send the SCSI Bus Reset end idle command which de-asserts
16747 * the SCSI Bus Reset signal and purges any pending requests.
16748 */
16749 status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
16750 if (status != ADV_TRUE) {
16751 return status;
16752 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016753
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016754 DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016755
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016756 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016757}
16758
16759/*
16760 * Reset chip and SCSI Bus.
16761 *
16762 * Return Value:
16763 * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful.
16764 * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure.
16765 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016766static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016767{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016768 int status;
16769 ushort wdtr_able, sdtr_able, tagqng_able;
16770 ushort ppr_able = 0;
16771 uchar tid, max_cmd[ADV_MAX_TID + 1];
16772 AdvPortAddr iop_base;
16773 ushort bios_sig;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016774
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016775 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016776
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016777 /*
16778 * Save current per TID negotiated values.
16779 */
16780 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16781 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16782 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16783 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16784 }
16785 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16786 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16787 AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16788 max_cmd[tid]);
16789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016790
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016791 /*
16792 * Force the AdvInitAsc3550/38C0800Driver() function to
16793 * perform a SCSI Bus Reset by clearing the BIOS signature word.
16794 * The initialization functions assumes a SCSI Bus Reset is not
16795 * needed if the BIOS signature word is present.
16796 */
16797 AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
16798 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016799
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016800 /*
16801 * Stop chip and reset it.
16802 */
16803 AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
16804 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
16805 DvcSleepMilliSecond(100);
16806 AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
16807 ADV_CTRL_REG_CMD_WR_IO_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016808
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016809 /*
16810 * Reset Adv Library error code, if any, and try
16811 * re-initializing the chip.
16812 */
16813 asc_dvc->err_code = 0;
16814 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16815 status = AdvInitAsc38C1600Driver(asc_dvc);
16816 } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16817 status = AdvInitAsc38C0800Driver(asc_dvc);
16818 } else {
16819 status = AdvInitAsc3550Driver(asc_dvc);
16820 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016821
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016822 /* Translate initialization return value to status value. */
16823 if (status == 0) {
16824 status = ADV_TRUE;
16825 } else {
16826 status = ADV_FALSE;
16827 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016828
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016829 /*
16830 * Restore the BIOS signature word.
16831 */
16832 AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016833
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016834 /*
16835 * Restore per TID negotiated values.
16836 */
16837 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
16838 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
16839 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
16840 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
16841 }
16842 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
16843 for (tid = 0; tid <= ADV_MAX_TID; tid++) {
16844 AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
16845 max_cmd[tid]);
16846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016847
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016848 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016849}
16850
16851/*
16852 * Adv Library Interrupt Service Routine
16853 *
16854 * This function is called by a driver's interrupt service routine.
16855 * The function disables and re-enables interrupts.
16856 *
16857 * When a microcode idle command is completed, the ADV_DVC_VAR
16858 * 'idle_cmd_done' field is set to ADV_TRUE.
16859 *
16860 * Note: AdvISR() can be called when interrupts are disabled or even
16861 * when there is no hardware interrupt condition present. It will
16862 * always check for completed idle commands and microcode requests.
16863 * This is an important feature that shouldn't be changed because it
16864 * allows commands to be completed from polling mode loops.
16865 *
16866 * Return:
16867 * ADV_TRUE(1) - interrupt was pending
16868 * ADV_FALSE(0) - no interrupt was pending
16869 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016870static int AdvISR(ADV_DVC_VAR *asc_dvc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070016871{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016872 AdvPortAddr iop_base;
16873 uchar int_stat;
16874 ushort target_bit;
16875 ADV_CARR_T *free_carrp;
16876 ADV_VADDR irq_next_vpa;
16877 int flags;
16878 ADV_SCSI_REQ_Q *scsiq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016879
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016880 flags = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070016881
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016882 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016883
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016884 /* Reading the register clears the interrupt. */
16885 int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016886
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016887 if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
16888 ADV_INTR_STATUS_INTRC)) == 0) {
16889 DvcLeaveCritical(flags);
16890 return ADV_FALSE;
16891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016892
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016893 /*
16894 * Notify the driver of an asynchronous microcode condition by
16895 * calling the ADV_DVC_VAR.async_callback function. The function
16896 * is passed the microcode ASC_MC_INTRB_CODE byte value.
16897 */
16898 if (int_stat & ADV_INTR_STATUS_INTRB) {
16899 uchar intrb_code;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016900
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016901 AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016902
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016903 if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
16904 asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
16905 if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
16906 asc_dvc->carr_pending_cnt != 0) {
16907 AdvWriteByteRegister(iop_base, IOPB_TICKLE,
16908 ADV_TICKLE_A);
16909 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
16910 AdvWriteByteRegister(iop_base,
16911 IOPB_TICKLE,
16912 ADV_TICKLE_NOP);
16913 }
16914 }
16915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016916
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016917 if (asc_dvc->async_callback != 0) {
16918 (*asc_dvc->async_callback) (asc_dvc, intrb_code);
16919 }
16920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016921
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016922 /*
16923 * Check if the IRQ stopper carrier contains a completed request.
16924 */
16925 while (((irq_next_vpa =
16926 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
16927 /*
16928 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
16929 * The RISC will have set 'areq_vpa' to a virtual address.
16930 *
16931 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
16932 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
16933 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
16934 * in AdvExeScsiQueue().
16935 */
16936 scsiq = (ADV_SCSI_REQ_Q *)
16937 ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016938
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016939 /*
16940 * Request finished with good status and the queue was not
16941 * DMAed to host memory by the firmware. Set all status fields
16942 * to indicate good status.
16943 */
16944 if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
16945 scsiq->done_status = QD_NO_ERROR;
16946 scsiq->host_status = scsiq->scsi_status = 0;
16947 scsiq->data_cnt = 0L;
16948 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016949
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016950 /*
16951 * Advance the stopper pointer to the next carrier
16952 * ignoring the lower four bits. Free the previous
16953 * stopper carrier.
16954 */
16955 free_carrp = asc_dvc->irq_sp;
16956 asc_dvc->irq_sp = (ADV_CARR_T *)
16957 ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
Linus Torvalds1da177e2005-04-16 15:20:36 -070016958
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016959 free_carrp->next_vpa =
16960 cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
16961 asc_dvc->carr_freelist = free_carrp;
16962 asc_dvc->carr_pending_cnt--;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016963
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016964 ASC_ASSERT(scsiq != NULL);
16965 target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070016966
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016967 /*
16968 * Clear request microcode control flag.
16969 */
16970 scsiq->cntl = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070016971
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016972 /*
16973 * If the command that completed was a SCSI INQUIRY and
16974 * LUN 0 was sent the command, then process the INQUIRY
16975 * command information for the device.
16976 *
16977 * Note: If data returned were either VPD or CmdDt data,
16978 * don't process the INQUIRY command information for
16979 * the device, otherwise may erroneously set *_able bits.
16980 */
16981 if (scsiq->done_status == QD_NO_ERROR &&
16982 scsiq->cdb[0] == INQUIRY &&
16983 scsiq->target_lun == 0 &&
16984 (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
16985 == ADV_INQ_RTN_STD_INQUIRY_DATA) {
16986 AdvInquiryHandling(asc_dvc, scsiq);
16987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070016988
Matthew Wilcox27c868c2007-07-26 10:56:23 -040016989 /*
16990 * Notify the driver of the completed request by passing
16991 * the ADV_SCSI_REQ_Q pointer to its callback function.
16992 */
16993 scsiq->a_flag |= ADV_SCSIQ_DONE;
16994 (*asc_dvc->isr_callback) (asc_dvc, scsiq);
16995 /*
16996 * Note: After the driver callback function is called, 'scsiq'
16997 * can no longer be referenced.
16998 *
16999 * Fall through and continue processing other completed
17000 * requests...
17001 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017002
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017003 /*
17004 * Disable interrupts again in case the driver inadvertently
17005 * enabled interrupts in its callback function.
17006 *
17007 * The DvcEnterCritical() return value is ignored, because
17008 * the 'flags' saved when AdvISR() was first entered will be
17009 * used to restore the interrupt flag on exit.
17010 */
17011 (void)DvcEnterCritical();
17012 }
17013 DvcLeaveCritical(flags);
17014 return ADV_TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017015}
17016
17017/*
17018 * Send an idle command to the chip and wait for completion.
17019 *
17020 * Command completion is polled for once per microsecond.
17021 *
17022 * The function can be called from anywhere including an interrupt handler.
17023 * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
17024 * functions to prevent reentrancy.
17025 *
17026 * Return Values:
17027 * ADV_TRUE - command completed successfully
17028 * ADV_FALSE - command failed
17029 * ADV_ERROR - command timed out
17030 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017031static int
Linus Torvalds1da177e2005-04-16 15:20:36 -070017032AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017033 ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017034{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017035 ulong last_int_level;
17036 int result;
17037 ADV_DCNT i, j;
17038 AdvPortAddr iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017039
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017040 last_int_level = DvcEnterCritical();
Linus Torvalds1da177e2005-04-16 15:20:36 -070017041
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017042 iop_base = asc_dvc->iop_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017043
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017044 /*
17045 * Clear the idle command status which is set by the microcode
17046 * to a non-zero value to indicate when the command is completed.
17047 * The non-zero result is one of the IDLE_CMD_STATUS_* values
17048 * defined in a_advlib.h.
17049 */
17050 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017051
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017052 /*
17053 * Write the idle command value after the idle command parameter
17054 * has been written to avoid a race condition. If the order is not
17055 * followed, the microcode may process the idle command before the
17056 * parameters have been written to LRAM.
17057 */
17058 AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
17059 cpu_to_le32(idle_cmd_parameter));
17060 AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017061
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017062 /*
17063 * Tickle the RISC to tell it to process the idle command.
17064 */
17065 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
17066 if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
17067 /*
17068 * Clear the tickle value. In the ASC-3550 the RISC flag
17069 * command 'clr_tickle_b' does not work unless the host
17070 * value is cleared.
17071 */
17072 AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
17073 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017074
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017075 /* Wait for up to 100 millisecond for the idle command to timeout. */
17076 for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
17077 /* Poll once each microsecond for command completion. */
17078 for (j = 0; j < SCSI_US_PER_MSEC; j++) {
17079 AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
17080 result);
17081 if (result != 0) {
17082 DvcLeaveCritical(last_int_level);
17083 return result;
17084 }
17085 DvcDelayMicroSecond(asc_dvc, (ushort)1);
17086 }
17087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017088
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017089 ASC_ASSERT(0); /* The idle command should never timeout. */
17090 DvcLeaveCritical(last_int_level);
17091 return ADV_ERROR;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017092}
17093
17094/*
17095 * Inquiry Information Byte 7 Handling
17096 *
17097 * Handle SCSI Inquiry Command information for a device by setting
17098 * microcode operating variables that affect WDTR, SDTR, and Tag
17099 * Queuing.
17100 */
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017101static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
Linus Torvalds1da177e2005-04-16 15:20:36 -070017102{
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017103 AdvPortAddr iop_base;
17104 uchar tid;
17105 ADV_SCSI_INQUIRY *inq;
17106 ushort tidmask;
17107 ushort cfg_word;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017108
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017109 /*
17110 * AdvInquiryHandling() requires up to INQUIRY information Byte 7
17111 * to be available.
17112 *
17113 * If less than 8 bytes of INQUIRY information were requested or less
17114 * than 8 bytes were transferred, then return. cdb[4] is the request
17115 * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
17116 * microcode to the transfer residual count.
17117 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017118
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017119 if (scsiq->cdb[4] < 8 ||
17120 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) {
17121 return;
17122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017123
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017124 iop_base = asc_dvc->iop_base;
17125 tid = scsiq->target_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017126
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017127 inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070017128
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017129 /*
17130 * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
17131 */
17132 if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) {
17133 return;
17134 } else {
17135 /*
17136 * INQUIRY Byte 7 Handling
17137 *
17138 * Use a device's INQUIRY byte 7 to determine whether it
17139 * supports WDTR, SDTR, and Tag Queuing. If the feature
17140 * is enabled in the EEPROM and the device supports the
17141 * feature, then enable it in the microcode.
17142 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070017143
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017144 tidmask = ADV_TID_TO_TIDMASK(tid);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017145
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017146 /*
17147 * Wide Transfers
17148 *
17149 * If the EEPROM enabled WDTR for the device and the device
17150 * supports wide bus (16 bit) transfers, then turn on the
17151 * device's 'wdtr_able' bit and write the new value to the
17152 * microcode.
17153 */
17154 if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) {
17155 AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
17156 if ((cfg_word & tidmask) == 0) {
17157 cfg_word |= tidmask;
17158 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
17159 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017160
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017161 /*
17162 * Clear the microcode "SDTR negotiation" and "WDTR
17163 * negotiation" done indicators for the target to cause
17164 * it to negotiate with the new setting set above.
17165 * WDTR when accepted causes the target to enter
17166 * asynchronous mode, so SDTR must be negotiated.
17167 */
17168 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17169 cfg_word);
17170 cfg_word &= ~tidmask;
17171 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17172 cfg_word);
17173 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE,
17174 cfg_word);
17175 cfg_word &= ~tidmask;
17176 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE,
17177 cfg_word);
17178 }
17179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017180
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017181 /*
17182 * Synchronous Transfers
17183 *
17184 * If the EEPROM enabled SDTR for the device and the device
17185 * supports synchronous transfers, then turn on the device's
17186 * 'sdtr_able' bit. Write the new value to the microcode.
17187 */
17188 if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) {
17189 AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
17190 if ((cfg_word & tidmask) == 0) {
17191 cfg_word |= tidmask;
17192 AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
17193 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017194
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017195 /*
17196 * Clear the microcode "SDTR negotiation" done indicator
17197 * for the target to cause it to negotiate with the new
17198 * setting set above.
17199 */
17200 AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
17201 cfg_word);
17202 cfg_word &= ~tidmask;
17203 AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
17204 cfg_word);
17205 }
17206 }
17207 /*
17208 * If the Inquiry data included enough space for the SPI-3
17209 * Clocking field, then check if DT mode is supported.
17210 */
17211 if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
17212 (scsiq->cdb[4] >= 57 ||
17213 (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) {
17214 /*
17215 * PPR (Parallel Protocol Request) Capable
17216 *
17217 * If the device supports DT mode, then it must be PPR capable.
17218 * The PPR message will be used in place of the SDTR and WDTR
17219 * messages to negotiate synchronous speed and offset, transfer
17220 * width, and protocol options.
17221 */
17222 if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) {
17223 AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE,
17224 asc_dvc->ppr_able);
17225 asc_dvc->ppr_able |= tidmask;
17226 AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE,
17227 asc_dvc->ppr_able);
17228 }
17229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017230
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017231 /*
17232 * If the EEPROM enabled Tag Queuing for the device and the
17233 * device supports Tag Queueing, then turn on the device's
17234 * 'tagqng_enable' bit in the microcode and set the microcode
17235 * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
17236 * value.
17237 *
17238 * Tag Queuing is disabled for the BIOS which runs in polled
17239 * mode and would see no benefit from Tag Queuing. Also by
17240 * disabling Tag Queuing in the BIOS devices with Tag Queuing
17241 * bugs will at least work with the BIOS.
17242 */
17243 if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) {
17244 AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
17245 cfg_word |= tidmask;
17246 AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
17247 cfg_word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070017248
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017249 AdvWriteByteLram(iop_base,
17250 ASC_MC_NUMBER_OF_MAX_CMD + tid,
17251 asc_dvc->max_dvc_qng);
17252 }
17253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070017254}
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017255
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017256static int __devinit
17257advansys_wide_init_chip(asc_board_t *boardp, ADV_DVC_VAR *adv_dvc_varp)
17258{
17259 int req_cnt = 0;
17260 adv_req_t *reqp = NULL;
17261 int sg_cnt = 0;
17262 adv_sgblk_t *sgp;
17263 int warn_code, err_code;
17264
17265 /*
17266 * Allocate buffer carrier structures. The total size
17267 * is about 4 KB, so allocate all at once.
17268 */
17269 boardp->carrp = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL);
17270 ASC_DBG1(1, "advansys_wide_init_chip: carrp 0x%p\n", boardp->carrp);
17271
17272 if (!boardp->carrp)
17273 goto kmalloc_failed;
17274
17275 /*
17276 * Allocate up to 'max_host_qng' request structures for the Wide
17277 * board. The total size is about 16 KB, so allocate all at once.
17278 * If the allocation fails decrement and try again.
17279 */
17280 for (req_cnt = adv_dvc_varp->max_host_qng; req_cnt > 0; req_cnt--) {
17281 reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL);
17282
17283 ASC_DBG3(1, "advansys_wide_init_chip: reqp 0x%p, req_cnt %d, "
17284 "bytes %lu\n", reqp, req_cnt,
17285 (ulong)sizeof(adv_req_t) * req_cnt);
17286
17287 if (reqp)
17288 break;
17289 }
17290
17291 if (!reqp)
17292 goto kmalloc_failed;
17293
17294 boardp->orig_reqp = reqp;
17295
17296 /*
17297 * Allocate up to ADV_TOT_SG_BLOCK request structures for
17298 * the Wide board. Each structure is about 136 bytes.
17299 */
17300 boardp->adv_sgblkp = NULL;
17301 for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
17302 sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL);
17303
17304 if (!sgp)
17305 break;
17306
17307 sgp->next_sgblkp = boardp->adv_sgblkp;
17308 boardp->adv_sgblkp = sgp;
17309
17310 }
17311
17312 ASC_DBG3(1, "advansys_wide_init_chip: sg_cnt %d * %u = %u bytes\n",
17313 sg_cnt, sizeof(adv_sgblk_t),
17314 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
17315
17316 if (!boardp->adv_sgblkp)
17317 goto kmalloc_failed;
17318
17319 adv_dvc_varp->carrier_buf = boardp->carrp;
17320
17321 /*
17322 * Point 'adv_reqp' to the request structures and
17323 * link them together.
17324 */
17325 req_cnt--;
17326 reqp[req_cnt].next_reqp = NULL;
17327 for (; req_cnt > 0; req_cnt--) {
17328 reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
17329 }
17330 boardp->adv_reqp = &reqp[0];
17331
17332 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17333 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc3550Driver()\n");
17334 warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
17335 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17336 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C0800Driver()"
17337 "\n");
17338 warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
17339 } else {
17340 ASC_DBG(2, "advansys_wide_init_chip: AdvInitAsc38C1600Driver()"
17341 "\n");
17342 warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
17343 }
17344 err_code = adv_dvc_varp->err_code;
17345
17346 if (warn_code || err_code) {
17347 ASC_PRINT3("advansys_wide_init_chip: board %d error: warn 0x%x,"
17348 " error 0x%x\n", boardp->id, warn_code, err_code);
17349 }
17350
17351 goto exit;
17352
17353 kmalloc_failed:
17354 ASC_PRINT1("advansys_wide_init_chip: board %d error: kmalloc() "
17355 "failed\n", boardp->id);
17356 err_code = ADV_ERROR;
17357 exit:
17358 return err_code;
17359}
17360
17361static void advansys_wide_free_mem(asc_board_t *boardp)
17362{
17363 kfree(boardp->carrp);
17364 boardp->carrp = NULL;
17365 kfree(boardp->orig_reqp);
17366 boardp->orig_reqp = boardp->adv_reqp = NULL;
17367 while (boardp->adv_sgblkp) {
17368 adv_sgblk_t *sgp = boardp->adv_sgblkp;
17369 boardp->adv_sgblkp = sgp->next_sgblkp;
17370 kfree(sgp);
17371 }
17372}
17373
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017374static struct Scsi_Host *__devinit
17375advansys_board_found(int iop, struct device *dev, int bus_type)
17376{
17377 struct Scsi_Host *shost;
17378 struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
17379 asc_board_t *boardp;
17380 ASC_DVC_VAR *asc_dvc_varp = NULL;
17381 ADV_DVC_VAR *adv_dvc_varp = NULL;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017382 int share_irq;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017383 int iolen = 0;
17384 ADV_PADDR pci_memory_address;
17385 int warn_code, err_code;
17386 int ret;
17387
17388 /*
17389 * Adapter found.
17390 *
17391 * Register the adapter, get its configuration, and
17392 * initialize it.
17393 */
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060017394 ASC_DBG(2, "advansys_board_found: scsi_host_alloc()\n");
17395 shost = scsi_host_alloc(&advansys_template, sizeof(asc_board_t));
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017396
17397 if (!shost)
17398 return NULL;
17399
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017400 /* Initialize private per board data */
17401 boardp = ASC_BOARDP(shost);
17402 memset(boardp, 0, sizeof(asc_board_t));
Matthew Wilcox78e77d82007-07-29 21:46:15 -060017403 boardp->id = asc_board_count++;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017404
17405 /* Initialize spinlock. */
17406 spin_lock_init(&boardp->lock);
17407
17408 /*
17409 * Handle both narrow and wide boards.
17410 *
17411 * If a Wide board was detected, set the board structure
17412 * wide board flag. Set-up the board structure based on
17413 * the board type.
17414 */
17415#ifdef CONFIG_PCI
17416 if (bus_type == ASC_IS_PCI &&
17417 (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
17418 pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
17419 pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
17420 boardp->flags |= ASC_IS_WIDE_BOARD;
17421 }
17422#endif /* CONFIG_PCI */
17423
17424 if (ASC_NARROW_BOARD(boardp)) {
17425 ASC_DBG(1, "advansys_board_found: narrow board\n");
17426 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
17427 asc_dvc_varp->bus_type = bus_type;
17428 asc_dvc_varp->drv_ptr = boardp;
17429 asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
17430 asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
17431 asc_dvc_varp->iop_base = iop;
17432 asc_dvc_varp->isr_callback = asc_isr_callback;
17433 } else {
17434 ASC_DBG(1, "advansys_board_found: wide board\n");
17435 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
17436 adv_dvc_varp->drv_ptr = boardp;
17437 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
17438 adv_dvc_varp->isr_callback = adv_isr_callback;
17439 adv_dvc_varp->async_callback = adv_async_callback;
17440#ifdef CONFIG_PCI
17441 if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
17442 ASC_DBG(1, "advansys_board_found: ASC-3550\n");
17443 adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
17444 } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
17445 ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
17446 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
17447 } else {
17448 ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
17449 adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
17450 }
17451#endif /* CONFIG_PCI */
17452
17453 /*
17454 * Map the board's registers into virtual memory for
17455 * PCI slave access. Only memory accesses are used to
17456 * access the board's registers.
17457 *
17458 * Note: The PCI register base address is not always
17459 * page aligned, but the address passed to ioremap()
17460 * must be page aligned. It is guaranteed that the
17461 * PCI register base address will not cross a page
17462 * boundary.
17463 */
17464 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17465 iolen = ADV_3550_IOLEN;
17466 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17467 iolen = ADV_38C0800_IOLEN;
17468 } else {
17469 iolen = ADV_38C1600_IOLEN;
17470 }
17471#ifdef CONFIG_PCI
17472 pci_memory_address = pci_resource_start(pdev, 1);
17473 ASC_DBG1(1,
17474 "advansys_board_found: pci_memory_address: 0x%lx\n",
17475 (ulong)pci_memory_address);
17476 if ((boardp->ioremap_addr =
17477 ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
17478 ASC_PRINT3
17479 ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
17480 boardp->id, pci_memory_address, iolen);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017481 goto err_shost;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017482 }
Matthew Wilcox71f36112007-07-30 08:04:53 -060017483 ASC_DBG1(1, "advansys_board_found: ioremap_addr: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017484 (ulong)boardp->ioremap_addr);
17485 adv_dvc_varp->iop_base = (AdvPortAddr)
17486 (boardp->ioremap_addr +
17487 (pci_memory_address - (pci_memory_address & PAGE_MASK)));
Matthew Wilcox71f36112007-07-30 08:04:53 -060017488 ASC_DBG1(1, "advansys_board_found: iop_base: 0x%lx\n",
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017489 adv_dvc_varp->iop_base);
17490#endif /* CONFIG_PCI */
17491
17492 /*
17493 * Even though it isn't used to access wide boards, other
17494 * than for the debug line below, save I/O Port address so
17495 * that it can be reported.
17496 */
17497 boardp->ioport = iop;
17498
17499 ASC_DBG2(1,
17500 "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
17501 (ushort)inp(iop + 1), (ushort)inpw(iop));
17502 }
17503
17504#ifdef CONFIG_PROC_FS
17505 /*
17506 * Allocate buffer for printing information from
17507 * /proc/scsi/advansys/[0...].
17508 */
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017509 boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL);
17510 if (!boardp->prtbuf) {
17511 ASC_PRINT2("advansys_board_found: board %d: kmalloc(%d) "
17512 "returned NULL\n", boardp->id, ASC_PRTBUF_SIZE);
17513 goto err_unmap;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017514 }
17515#endif /* CONFIG_PROC_FS */
17516
17517 if (ASC_NARROW_BOARD(boardp)) {
17518 asc_dvc_varp->cfg->dev = dev;
17519 /*
17520 * Set the board bus type and PCI IRQ before
17521 * calling AscInitGetConfig().
17522 */
17523 switch (asc_dvc_varp->bus_type) {
17524#ifdef CONFIG_ISA
17525 case ASC_IS_ISA:
17526 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017527 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017528 break;
17529 case ASC_IS_VL:
17530 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017531 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017532 break;
17533 case ASC_IS_EISA:
17534 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017535 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017536 break;
17537#endif /* CONFIG_ISA */
17538#ifdef CONFIG_PCI
17539 case ASC_IS_PCI:
17540 shost->irq = asc_dvc_varp->irq_no = pdev->irq;
17541 asc_dvc_varp->cfg->pci_slot_info =
17542 ASC_PCI_MKID(pdev->bus->number,
17543 PCI_SLOT(pdev->devfn),
17544 PCI_FUNC(pdev->devfn));
17545 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017546 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017547 break;
17548#endif /* CONFIG_PCI */
17549 default:
17550 ASC_PRINT2
17551 ("advansys_board_found: board %d: unknown adapter type: %d\n",
17552 boardp->id, asc_dvc_varp->bus_type);
17553 shost->unchecked_isa_dma = TRUE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017554 share_irq = 0;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017555 break;
17556 }
17557 } else {
17558 adv_dvc_varp->cfg->dev = dev;
17559 /*
17560 * For Wide boards set PCI information before calling
17561 * AdvInitGetConfig().
17562 */
17563#ifdef CONFIG_PCI
17564 shost->irq = adv_dvc_varp->irq_no = pdev->irq;
17565 adv_dvc_varp->cfg->pci_slot_info =
17566 ASC_PCI_MKID(pdev->bus->number,
17567 PCI_SLOT(pdev->devfn),
17568 PCI_FUNC(pdev->devfn));
17569 shost->unchecked_isa_dma = FALSE;
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017570 share_irq = IRQF_SHARED;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017571#endif /* CONFIG_PCI */
17572 }
17573
17574 /*
17575 * Read the board configuration.
17576 */
17577 if (ASC_NARROW_BOARD(boardp)) {
17578 /*
17579 * NOTE: AscInitGetConfig() may change the board's
17580 * bus_type value. The bus_type value should no
17581 * longer be used. If the bus_type field must be
17582 * referenced only use the bit-wise AND operator "&".
17583 */
17584 ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
17585 switch (ret = AscInitGetConfig(asc_dvc_varp)) {
17586 case 0: /* No error */
17587 break;
17588 case ASC_WARN_IO_PORT_ROTATE:
17589 ASC_PRINT1
17590 ("AscInitGetConfig: board %d: I/O port address modified\n",
17591 boardp->id);
17592 break;
17593 case ASC_WARN_AUTO_CONFIG:
17594 ASC_PRINT1
17595 ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
17596 boardp->id);
17597 break;
17598 case ASC_WARN_EEPROM_CHKSUM:
17599 ASC_PRINT1
17600 ("AscInitGetConfig: board %d: EEPROM checksum error\n",
17601 boardp->id);
17602 break;
17603 case ASC_WARN_IRQ_MODIFIED:
17604 ASC_PRINT1
17605 ("AscInitGetConfig: board %d: IRQ modified\n",
17606 boardp->id);
17607 break;
17608 case ASC_WARN_CMD_QNG_CONFLICT:
17609 ASC_PRINT1
17610 ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
17611 boardp->id);
17612 break;
17613 default:
17614 ASC_PRINT2
17615 ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
17616 boardp->id, ret);
17617 break;
17618 }
17619 if ((err_code = asc_dvc_varp->err_code) != 0) {
17620 ASC_PRINT3
17621 ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17622 boardp->id,
17623 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
17624 }
17625 } else {
17626 ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
17627 if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
17628 ASC_PRINT2
17629 ("AdvInitGetConfig: board %d: warning: 0x%x\n",
17630 boardp->id, ret);
17631 }
17632 if ((err_code = adv_dvc_varp->err_code) != 0) {
17633 ASC_PRINT2
17634 ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
17635 boardp->id, adv_dvc_varp->err_code);
17636 }
17637 }
17638
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017639 if (err_code != 0)
17640 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017641
17642 /*
17643 * Save the EEPROM configuration so that it can be displayed
17644 * from /proc/scsi/advansys/[0...].
17645 */
17646 if (ASC_NARROW_BOARD(boardp)) {
17647
17648 ASCEEP_CONFIG *ep;
17649
17650 /*
17651 * Set the adapter's target id bit in the 'init_tidmask' field.
17652 */
17653 boardp->init_tidmask |=
17654 ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
17655
17656 /*
17657 * Save EEPROM settings for the board.
17658 */
17659 ep = &boardp->eep_config.asc_eep;
17660
17661 ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
17662 ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
17663 ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
17664 ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
17665 ep->start_motor = asc_dvc_varp->start_motor;
17666 ep->cntl = asc_dvc_varp->dvc_cntl;
17667 ep->no_scam = asc_dvc_varp->no_scam;
17668 ep->max_total_qng = asc_dvc_varp->max_total_qng;
17669 ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
17670 /* 'max_tag_qng' is set to the same value for every device. */
17671 ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
17672 ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
17673 ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
17674 ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
17675 ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
17676 ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
17677 ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
17678
17679 /*
17680 * Modify board configuration.
17681 */
17682 ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
17683 switch (ret = AscInitSetConfig(asc_dvc_varp)) {
17684 case 0: /* No error. */
17685 break;
17686 case ASC_WARN_IO_PORT_ROTATE:
17687 ASC_PRINT1
17688 ("AscInitSetConfig: board %d: I/O port address modified\n",
17689 boardp->id);
17690 break;
17691 case ASC_WARN_AUTO_CONFIG:
17692 ASC_PRINT1
17693 ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
17694 boardp->id);
17695 break;
17696 case ASC_WARN_EEPROM_CHKSUM:
17697 ASC_PRINT1
17698 ("AscInitSetConfig: board %d: EEPROM checksum error\n",
17699 boardp->id);
17700 break;
17701 case ASC_WARN_IRQ_MODIFIED:
17702 ASC_PRINT1
17703 ("AscInitSetConfig: board %d: IRQ modified\n",
17704 boardp->id);
17705 break;
17706 case ASC_WARN_CMD_QNG_CONFLICT:
17707 ASC_PRINT1
17708 ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
17709 boardp->id);
17710 break;
17711 default:
17712 ASC_PRINT2
17713 ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
17714 boardp->id, ret);
17715 break;
17716 }
17717 if (asc_dvc_varp->err_code != 0) {
17718 ASC_PRINT3
17719 ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
17720 boardp->id,
17721 asc_dvc_varp->init_state, asc_dvc_varp->err_code);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017722 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017723 }
17724
17725 /*
17726 * Finish initializing the 'Scsi_Host' structure.
17727 */
17728 /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
17729 if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
17730 shost->irq = asc_dvc_varp->irq_no;
17731 }
17732 } else {
17733 ADVEEP_3550_CONFIG *ep_3550;
17734 ADVEEP_38C0800_CONFIG *ep_38C0800;
17735 ADVEEP_38C1600_CONFIG *ep_38C1600;
17736
17737 /*
17738 * Save Wide EEP Configuration Information.
17739 */
17740 if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
17741 ep_3550 = &boardp->eep_config.adv_3550_eep;
17742
17743 ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
17744 ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
17745 ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17746 ep_3550->termination = adv_dvc_varp->cfg->termination;
17747 ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
17748 ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
17749 ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
17750 ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
17751 ep_3550->ultra_able = adv_dvc_varp->ultra_able;
17752 ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
17753 ep_3550->start_motor = adv_dvc_varp->start_motor;
17754 ep_3550->scsi_reset_delay =
17755 adv_dvc_varp->scsi_reset_wait;
17756 ep_3550->serial_number_word1 =
17757 adv_dvc_varp->cfg->serial1;
17758 ep_3550->serial_number_word2 =
17759 adv_dvc_varp->cfg->serial2;
17760 ep_3550->serial_number_word3 =
17761 adv_dvc_varp->cfg->serial3;
17762 } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
17763 ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
17764
17765 ep_38C0800->adapter_scsi_id =
17766 adv_dvc_varp->chip_scsi_id;
17767 ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
17768 ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17769 ep_38C0800->termination_lvd =
17770 adv_dvc_varp->cfg->termination;
17771 ep_38C0800->disc_enable =
17772 adv_dvc_varp->cfg->disc_enable;
17773 ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
17774 ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
17775 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17776 ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17777 ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17778 ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17779 ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17780 ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
17781 ep_38C0800->start_motor = adv_dvc_varp->start_motor;
17782 ep_38C0800->scsi_reset_delay =
17783 adv_dvc_varp->scsi_reset_wait;
17784 ep_38C0800->serial_number_word1 =
17785 adv_dvc_varp->cfg->serial1;
17786 ep_38C0800->serial_number_word2 =
17787 adv_dvc_varp->cfg->serial2;
17788 ep_38C0800->serial_number_word3 =
17789 adv_dvc_varp->cfg->serial3;
17790 } else {
17791 ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
17792
17793 ep_38C1600->adapter_scsi_id =
17794 adv_dvc_varp->chip_scsi_id;
17795 ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
17796 ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
17797 ep_38C1600->termination_lvd =
17798 adv_dvc_varp->cfg->termination;
17799 ep_38C1600->disc_enable =
17800 adv_dvc_varp->cfg->disc_enable;
17801 ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
17802 ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
17803 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17804 ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
17805 ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
17806 ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
17807 ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
17808 ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
17809 ep_38C1600->start_motor = adv_dvc_varp->start_motor;
17810 ep_38C1600->scsi_reset_delay =
17811 adv_dvc_varp->scsi_reset_wait;
17812 ep_38C1600->serial_number_word1 =
17813 adv_dvc_varp->cfg->serial1;
17814 ep_38C1600->serial_number_word2 =
17815 adv_dvc_varp->cfg->serial2;
17816 ep_38C1600->serial_number_word3 =
17817 adv_dvc_varp->cfg->serial3;
17818 }
17819
17820 /*
17821 * Set the adapter's target id bit in the 'init_tidmask' field.
17822 */
17823 boardp->init_tidmask |=
17824 ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
17825
17826 /*
17827 * Finish initializing the 'Scsi_Host' structure.
17828 */
17829 shost->irq = adv_dvc_varp->irq_no;
17830 }
17831
17832 /*
17833 * Channels are numbered beginning with 0. For AdvanSys one host
17834 * structure supports one channel. Multi-channel boards have a
17835 * separate host structure for each channel.
17836 */
17837 shost->max_channel = 0;
17838 if (ASC_NARROW_BOARD(boardp)) {
17839 shost->max_id = ASC_MAX_TID + 1;
17840 shost->max_lun = ASC_MAX_LUN + 1;
17841
17842 shost->io_port = asc_dvc_varp->iop_base;
17843 boardp->asc_n_io_port = ASC_IOADR_GAP;
17844 shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
17845
17846 /* Set maximum number of queues the adapter can handle. */
17847 shost->can_queue = asc_dvc_varp->max_total_qng;
17848 } else {
17849 shost->max_id = ADV_MAX_TID + 1;
17850 shost->max_lun = ADV_MAX_LUN + 1;
17851
17852 /*
17853 * Save the I/O Port address and length even though
17854 * I/O ports are not used to access Wide boards.
17855 * Instead the Wide boards are accessed with
17856 * PCI Memory Mapped I/O.
17857 */
17858 shost->io_port = iop;
17859 boardp->asc_n_io_port = iolen;
17860
17861 shost->this_id = adv_dvc_varp->chip_scsi_id;
17862
17863 /* Set maximum number of queues the adapter can handle. */
17864 shost->can_queue = adv_dvc_varp->max_host_qng;
17865 }
17866
17867 /*
17868 * 'n_io_port' currently is one byte.
17869 *
17870 * Set a value to 'n_io_port', but never referenced it because
17871 * it may be truncated.
17872 */
17873 shost->n_io_port = boardp->asc_n_io_port <= 255 ?
17874 boardp->asc_n_io_port : 255;
17875
17876 /*
17877 * Following v1.3.89, 'cmd_per_lun' is no longer needed
17878 * and should be set to zero.
17879 *
17880 * But because of a bug introduced in v1.3.89 if the driver is
17881 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
17882 * SCSI function 'allocate_device' will panic. To allow the driver
17883 * to work as a module in these kernels set 'cmd_per_lun' to 1.
17884 *
17885 * Note: This is wrong. cmd_per_lun should be set to the depth
17886 * you want on untagged devices always.
17887 #ifdef MODULE
17888 */
17889 shost->cmd_per_lun = 1;
17890/* #else
17891 shost->cmd_per_lun = 0;
17892#endif */
17893
17894 /*
17895 * Set the maximum number of scatter-gather elements the
17896 * adapter can handle.
17897 */
17898 if (ASC_NARROW_BOARD(boardp)) {
17899 /*
17900 * Allow two commands with 'sg_tablesize' scatter-gather
17901 * elements to be executed simultaneously. This value is
17902 * the theoretical hardware limit. It may be decreased
17903 * below.
17904 */
17905 shost->sg_tablesize =
17906 (((asc_dvc_varp->max_total_qng - 2) / 2) *
17907 ASC_SG_LIST_PER_Q) + 1;
17908 } else {
17909 shost->sg_tablesize = ADV_MAX_SG_LIST;
17910 }
17911
17912 /*
17913 * The value of 'sg_tablesize' can not exceed the SCSI
17914 * mid-level driver definition of SG_ALL. SG_ALL also
17915 * must not be exceeded, because it is used to define the
17916 * size of the scatter-gather table in 'struct asc_sg_head'.
17917 */
17918 if (shost->sg_tablesize > SG_ALL) {
17919 shost->sg_tablesize = SG_ALL;
17920 }
17921
17922 ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
17923
17924 /* BIOS start address. */
17925 if (ASC_NARROW_BOARD(boardp)) {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017926 shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base,
17927 asc_dvc_varp->bus_type);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017928 } else {
17929 /*
17930 * Fill-in BIOS board variables. The Wide BIOS saves
17931 * information in LRAM that is used by the driver.
17932 */
17933 AdvReadWordLram(adv_dvc_varp->iop_base,
17934 BIOS_SIGNATURE, boardp->bios_signature);
17935 AdvReadWordLram(adv_dvc_varp->iop_base,
17936 BIOS_VERSION, boardp->bios_version);
17937 AdvReadWordLram(adv_dvc_varp->iop_base,
17938 BIOS_CODESEG, boardp->bios_codeseg);
17939 AdvReadWordLram(adv_dvc_varp->iop_base,
17940 BIOS_CODELEN, boardp->bios_codelen);
17941
17942 ASC_DBG2(1,
17943 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
17944 boardp->bios_signature, boardp->bios_version);
17945
17946 ASC_DBG2(1,
17947 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
17948 boardp->bios_codeseg, boardp->bios_codelen);
17949
17950 /*
17951 * If the BIOS saved a valid signature, then fill in
17952 * the BIOS code segment base address.
17953 */
17954 if (boardp->bios_signature == 0x55AA) {
17955 /*
17956 * Convert x86 realmode code segment to a linear
17957 * address by shifting left 4.
17958 */
17959 shost->base = ((ulong)boardp->bios_codeseg << 4);
17960 } else {
17961 shost->base = 0;
17962 }
17963 }
17964
17965 /*
17966 * Register Board Resources - I/O Port, DMA, IRQ
17967 */
17968
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017969 /* Register DMA Channel for Narrow boards. */
17970 shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
17971#ifdef CONFIG_ISA
17972 if (ASC_NARROW_BOARD(boardp)) {
17973 /* Register DMA channel for ISA bus. */
17974 if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
17975 shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060017976 ret = request_dma(shost->dma_channel, "advansys");
17977 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017978 ASC_PRINT3
17979 ("advansys_board_found: board %d: request_dma() %d failed %d\n",
17980 boardp->id, shost->dma_channel, ret);
Matthew Wilcox71f36112007-07-30 08:04:53 -060017981 goto err_free_proc;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017982 }
17983 AscEnableIsaDma(shost->dma_channel);
17984 }
17985 }
17986#endif /* CONFIG_ISA */
17987
17988 /* Register IRQ Number. */
17989 ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060017990
17991 ret = request_irq(shost->irq, advansys_interrupt, share_irq,
17992 "advansys", shost);
17993
17994 if (ret) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040017995 if (ret == -EBUSY) {
17996 ASC_PRINT2
17997 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
17998 boardp->id, shost->irq);
17999 } else if (ret == -EINVAL) {
18000 ASC_PRINT2
18001 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
18002 boardp->id, shost->irq);
18003 } else {
18004 ASC_PRINT3
18005 ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
18006 boardp->id, shost->irq, ret);
18007 }
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018008 goto err_free_dma;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018009 }
18010
18011 /*
18012 * Initialize board RISC chip and enable interrupts.
18013 */
18014 if (ASC_NARROW_BOARD(boardp)) {
18015 ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
18016 warn_code = AscInitAsc1000Driver(asc_dvc_varp);
18017 err_code = asc_dvc_varp->err_code;
18018
18019 if (warn_code || err_code) {
18020 ASC_PRINT4
18021 ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
18022 boardp->id,
18023 asc_dvc_varp->init_state, warn_code, err_code);
18024 }
18025 } else {
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018026 err_code = advansys_wide_init_chip(boardp, adv_dvc_varp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018027 }
18028
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018029 if (err_code != 0)
18030 goto err_free_wide_mem;
18031
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018032 ASC_DBG_PRT_SCSI_HOST(2, shost);
18033
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018034 ret = scsi_add_host(shost, dev);
18035 if (ret)
18036 goto err_free_wide_mem;
18037
18038 scsi_scan_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018039 return shost;
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018040
18041 err_free_wide_mem:
18042 advansys_wide_free_mem(boardp);
18043 free_irq(shost->irq, shost);
18044 err_free_dma:
18045 if (shost->dma_channel != NO_ISA_DMA)
18046 free_dma(shost->dma_channel);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018047 err_free_proc:
18048 kfree(boardp->prtbuf);
18049 err_unmap:
18050 if (boardp->ioremap_addr)
18051 iounmap(boardp->ioremap_addr);
18052 err_shost:
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018053 scsi_host_put(shost);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018054 return NULL;
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018055}
18056
18057/*
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018058 * advansys_release()
18059 *
18060 * Release resources allocated for a single AdvanSys adapter.
18061 */
18062static int advansys_release(struct Scsi_Host *shost)
18063{
18064 asc_board_t *boardp;
18065
18066 ASC_DBG(1, "advansys_release: begin\n");
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018067 scsi_remove_host(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018068 boardp = ASC_BOARDP(shost);
Matthew Wilcox074c8fe2007-07-28 23:11:05 -060018069 free_irq(shost->irq, shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018070 if (shost->dma_channel != NO_ISA_DMA) {
18071 ASC_DBG(1, "advansys_release: free_dma()\n");
18072 free_dma(shost->dma_channel);
18073 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018074 if (ASC_WIDE_BOARD(boardp)) {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018075 iounmap(boardp->ioremap_addr);
Matthew Wilcoxb2c16f52007-07-29 17:30:28 -060018076 advansys_wide_free_mem(boardp);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018077 }
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018078 kfree(boardp->prtbuf);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018079 scsi_host_put(shost);
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018080 ASC_DBG(1, "advansys_release: end\n");
18081 return 0;
18082}
18083
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018084static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __devinitdata = {
18085 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190,
18086 0x0210, 0x0230, 0x0250, 0x0330
18087};
18088
18089static int __devinit advansys_isa_probe(struct device *dev, unsigned int id)
18090{
18091 PortAddr iop_base = _asc_def_iop_base[id];
18092 struct Scsi_Host *shost;
18093
18094 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060018095 ASC_DBG1(1, "advansys_isa_match: I/O port 0x%x busy\n",
18096 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018097 return -ENODEV;
18098 }
18099 ASC_DBG1(1, "advansys_isa_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018100 if (!AscFindSignature(iop_base))
18101 goto nodev;
18102 if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT))
18103 goto nodev;
18104
18105 shost = advansys_board_found(iop_base, dev, ASC_IS_ISA);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018106 if (!shost)
18107 goto nodev;
18108
18109 dev_set_drvdata(dev, shost);
18110 return 0;
18111
18112 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060018113 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018114 return -ENODEV;
18115}
18116
18117static int __devexit advansys_isa_remove(struct device *dev, unsigned int id)
18118{
Matthew Wilcox71f36112007-07-30 08:04:53 -060018119 int ioport = _asc_def_iop_base[id];
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018120 advansys_release(dev_get_drvdata(dev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060018121 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018122 return 0;
18123}
18124
18125static struct isa_driver advansys_isa_driver = {
18126 .probe = advansys_isa_probe,
18127 .remove = __devexit_p(advansys_isa_remove),
18128 .driver = {
18129 .owner = THIS_MODULE,
18130 .name = "advansys",
18131 },
18132};
18133
18134static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id)
18135{
18136 PortAddr iop_base = _asc_def_iop_base[id];
18137 struct Scsi_Host *shost;
18138
18139 if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060018140 ASC_DBG1(1, "advansys_vlb_match: I/O port 0x%x busy\n",
18141 iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018142 return -ENODEV;
18143 }
18144 ASC_DBG1(1, "advansys_vlb_match: probing I/O port 0x%x\n", iop_base);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018145 if (!AscFindSignature(iop_base))
18146 goto nodev;
18147 /*
18148 * I don't think this condition can actually happen, but the old
18149 * driver did it, and the chances of finding a VLB setup in 2007
18150 * to do testing with is slight to none.
18151 */
18152 if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL)
18153 goto nodev;
18154
18155 shost = advansys_board_found(iop_base, dev, ASC_IS_VL);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018156 if (!shost)
18157 goto nodev;
18158
18159 dev_set_drvdata(dev, shost);
18160 return 0;
18161
18162 nodev:
Matthew Wilcox71f36112007-07-30 08:04:53 -060018163 release_region(iop_base, ASC_IOADR_GAP);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018164 return -ENODEV;
18165}
18166
18167static struct isa_driver advansys_vlb_driver = {
18168 .probe = advansys_vlb_probe,
18169 .remove = __devexit_p(advansys_isa_remove),
18170 .driver = {
18171 .owner = THIS_MODULE,
18172 .name = "advansys",
18173 },
18174};
18175
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018176static struct eisa_device_id advansys_eisa_table[] __devinitdata = {
18177 { "ABP7401" },
18178 { "ABP7501" },
18179 { "" }
18180};
18181
18182MODULE_DEVICE_TABLE(eisa, advansys_eisa_table);
18183
18184/*
18185 * EISA is a little more tricky than PCI; each EISA device may have two
18186 * channels, and this driver is written to make each channel its own Scsi_Host
18187 */
18188struct eisa_scsi_data {
18189 struct Scsi_Host *host[2];
18190};
18191
18192static int __devinit advansys_eisa_probe(struct device *dev)
18193{
18194 int i, ioport;
18195 int err;
18196 struct eisa_device *edev = to_eisa_device(dev);
18197 struct eisa_scsi_data *data;
18198
18199 err = -ENOMEM;
18200 data = kzalloc(sizeof(*data), GFP_KERNEL);
18201 if (!data)
18202 goto fail;
18203 ioport = edev->base_addr + 0xc30;
18204
18205 err = -ENODEV;
18206 for (i = 0; i < 2; i++, ioport += 0x20) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060018207 if (!request_region(ioport, ASC_IOADR_GAP, "advansys")) {
18208 printk(KERN_WARNING "Region %x-%x busy\n", ioport,
18209 ioport + ASC_IOADR_GAP - 1);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018210 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018211 }
18212 if (!AscFindSignature(ioport)) {
18213 release_region(ioport, ASC_IOADR_GAP);
18214 continue;
18215 }
18216
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018217 /*
18218 * I don't know why we need to do this for EISA chips, but
18219 * not for any others. It looks to be equivalent to
18220 * AscGetChipCfgMsw, but I may have overlooked something,
18221 * so I'm not converting it until I get an EISA board to
18222 * test with.
18223 */
18224 inw(ioport + 4);
18225 data->host[i] = advansys_board_found(ioport, dev, ASC_IS_EISA);
Matthew Wilcox71f36112007-07-30 08:04:53 -060018226 if (data->host[i]) {
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018227 err = 0;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018228 } else {
18229 release_region(ioport, ASC_IOADR_GAP);
18230 }
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018231 }
18232
18233 if (err) {
18234 kfree(data);
18235 } else {
18236 dev_set_drvdata(dev, data);
18237 }
18238
18239 fail:
18240 return err;
18241}
18242
18243static __devexit int advansys_eisa_remove(struct device *dev)
18244{
18245 int i;
18246 struct eisa_scsi_data *data = dev_get_drvdata(dev);
18247
18248 for (i = 0; i < 2; i++) {
Matthew Wilcox71f36112007-07-30 08:04:53 -060018249 int ioport;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018250 struct Scsi_Host *shost = data->host[i];
18251 if (!shost)
18252 continue;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018253 ioport = shost->io_port;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018254 advansys_release(shost);
Matthew Wilcox71f36112007-07-30 08:04:53 -060018255 release_region(ioport, ASC_IOADR_GAP);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018256 }
18257
18258 kfree(data);
18259 return 0;
18260}
18261
18262static struct eisa_driver advansys_eisa_driver = {
18263 .id_table = advansys_eisa_table,
18264 .driver = {
18265 .name = "advansys",
18266 .probe = advansys_eisa_probe,
18267 .remove = __devexit_p(advansys_eisa_remove),
18268 }
18269};
18270
Dave Jones2672ea82006-08-02 17:11:49 -040018271/* PCI Devices supported by this driver */
18272static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018273 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
18274 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18275 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
18276 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18277 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
18278 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18279 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
18280 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18281 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
18282 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18283 {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
18284 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
18285 {}
Dave Jones2672ea82006-08-02 17:11:49 -040018286};
Matthew Wilcox27c868c2007-07-26 10:56:23 -040018287
Dave Jones2672ea82006-08-02 17:11:49 -040018288MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018289
Matthew Wilcox9649af32007-07-26 21:51:47 -060018290static void __devinit advansys_set_latency(struct pci_dev *pdev)
18291{
18292 if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) ||
18293 (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) {
18294 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0);
18295 } else {
18296 u8 latency;
18297 pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
18298 if (latency < 0x20)
18299 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
18300 }
18301}
18302
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018303static int __devinit
18304advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
18305{
18306 int err, ioport;
18307 struct Scsi_Host *shost;
18308
18309 err = pci_enable_device(pdev);
18310 if (err)
18311 goto fail;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018312 err = pci_request_regions(pdev, "advansys");
18313 if (err)
18314 goto disable_device;
Matthew Wilcox9649af32007-07-26 21:51:47 -060018315 pci_set_master(pdev);
18316 advansys_set_latency(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018317
18318 if (pci_resource_len(pdev, 0) == 0)
18319 goto nodev;
18320
18321 ioport = pci_resource_start(pdev, 0);
18322 shost = advansys_board_found(ioport, &pdev->dev, ASC_IS_PCI);
18323
18324 if (!shost)
18325 goto nodev;
18326
18327 pci_set_drvdata(pdev, shost);
18328 return 0;
18329
18330 nodev:
18331 err = -ENODEV;
Matthew Wilcox71f36112007-07-30 08:04:53 -060018332 pci_release_regions(pdev);
18333 disable_device:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018334 pci_disable_device(pdev);
18335 fail:
18336 return err;
18337}
18338
18339static void __devexit advansys_pci_remove(struct pci_dev *pdev)
18340{
18341 advansys_release(pci_get_drvdata(pdev));
Matthew Wilcox71f36112007-07-30 08:04:53 -060018342 pci_release_regions(pdev);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018343 pci_disable_device(pdev);
18344}
18345
18346static struct pci_driver advansys_pci_driver = {
18347 .name = "advansys",
18348 .id_table = advansys_pci_tbl,
18349 .probe = advansys_pci_probe,
18350 .remove = __devexit_p(advansys_pci_remove),
18351};
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018352
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018353static int __init advansys_init(void)
18354{
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018355 int error;
18356
18357 error = isa_register_driver(&advansys_isa_driver,
18358 ASC_IOADR_TABLE_MAX_IX);
18359 if (error)
18360 goto fail;
18361
18362 error = isa_register_driver(&advansys_vlb_driver,
18363 ASC_IOADR_TABLE_MAX_IX);
18364 if (error)
18365 goto unregister_isa;
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018366
18367 error = eisa_driver_register(&advansys_eisa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018368 if (error)
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018369 goto unregister_vlb;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018370
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018371 error = pci_register_driver(&advansys_pci_driver);
18372 if (error)
18373 goto unregister_eisa;
18374
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018375 return 0;
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018376
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018377 unregister_eisa:
18378 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018379 unregister_vlb:
18380 isa_unregister_driver(&advansys_vlb_driver);
18381 unregister_isa:
18382 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018383 fail:
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018384 return error;
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018385}
18386
18387static void __exit advansys_exit(void)
18388{
Matthew Wilcox78e77d82007-07-29 21:46:15 -060018389 pci_unregister_driver(&advansys_pci_driver);
Matthew Wilcoxb09e05a2007-07-30 09:14:52 -060018390 eisa_driver_unregister(&advansys_eisa_driver);
Matthew Wilcoxc304ec92007-07-30 09:18:45 -060018391 isa_unregister_driver(&advansys_vlb_driver);
18392 isa_unregister_driver(&advansys_isa_driver);
Matthew Wilcox8dfb5372007-07-30 09:08:34 -060018393}
18394
18395module_init(advansys_init);
18396module_exit(advansys_exit);
18397
Matthew Wilcox8c6af9e2007-07-26 11:03:19 -040018398MODULE_LICENSE("GPL");